Find your landing page message
Connect a product’s value to a specific audience and write a clear first-screen message.
Generate images, text, audio, video, and transcribe speech via the Pollinations API using the polli CLI. Use when asked to generate media, call pollinations.ai, check pollen balance, list models, manage API keys, or run polli commands.
---
name: polli
description: Generate images, text, audio, video, and transcribe speech via the Pollinations API using the polli CLI. Use when asked to generate media, call pollinations.ai, check pollen balance, list models, manage API keys, inspect quests, manage agents or my-models, publish a static site, or run polli commands.
allowed-tools: Bash(polli *)
---
# polli — Pollinations CLI
Thin wrapper around `gen.pollinations.ai`. Generates images, text, audio, video; transcribes speech; manages API keys, usage, quests, agents, and invite-only my-models.
If `polli` is not installed, run `npm i -g @pollinations/cli@latest` (provides the `polli` binary).
## When to use this skill
- User asks to **generate an image / text / audio / video** via pollinations
- User mentions **polli, pollinations, pollen, pollinations.ai**
- User wants to **transcribe speech** or run TTS
- User asks about their **pollen balance, usage, or API keys**
- User wants to **browse or filter available models**
- User wants to inspect **quests** or manage invite-only **my-models**
- User wants to create or update a hosted prompt **agent**
- User wants to **publish a website or web app** they built
For agent-assisted login, use `polli --json auth login --no-browser`. Read stderr while the command runs and show the user the verification URL and user code so they can review access. On approval, stdout contains one JSON result: `{"authenticated":true}`. Tokens are stored locally and never included in that result.
## Quick reference
| Intent | Command |
|---|---|
| Log in once | `polli auth login` |
| Agent-assisted login | `polli --json auth login --no-browser` |
| Store an existing key | `printf '%s' "$POLLINATIONS_API_KEY" \| polli auth login --with-token` |
| Generate image | `polli gen image "<prompt>" --output out.png` |
| Generate text | `polli gen text "<prompt>"` |
| Text with stdin as context | `echo "<ctx>" \| polli gen text "<question>"` |
| Describe an image (vision) | `polli gen text "what is this?" --image <url>` |
| One-shot TTS | `polli gen audio "<text>" --output speech.mp3` |
| Speak out loud | `polli gen audio "<text>" --play` (uses `afplay` on macOS; `ffplay`/`mpv`/`mpg123` on Linux) |
| Generate video | `polli gen video "<prompt>" --output out.mp4` |
| Generate a 3D model | `polli gen 3d "<prompt>" --output out.glb` (or `--image <url>` for image-only models) |
| Embed text | `polli gen embeddings "<text>" ["<text2>" ...]` (one vector per line; also reads stdin) |
| Change a voice | `polli gen voice-change talk.mp3 --voice nova` |
| Isolate speech | `polli gen isolate interview.mp4` (strips music/noise) |
| Speech + character timings | `polli gen audio "<text>" --timestamps` (also writes `speech.mp3.json`) |
| Transcribe audio | `polli gen transcribe path/to.mp3` |
| Upload a local file | `polli upload path/to.png` (prints public URL) |
| List all models | `polli models` |
| Search models | `polli models <query>` (`--source official\|community`, `--reliability all`) |
| Discover voices | `polli models --type audio --voices` (one line per model) |
| Filter models by type | `polli models --type image` (text, decision, image, audio, video, 3d, embedding, realtime) |
| Model health + latency | `polli models --stats` (default 60m, `--window <min>`) |
| Check balance | `polli usage` |
| Developer earnings | `polli earnings` (`--days <n>`) |
| List your quests + claim state | `polli quests` (filters: `--open --claimable --claimed --coming-soon`) |
| Manage prompt agents | `polli agents list` |
| Manage invite-only community models | `polli my-models list` |
| Update the CLI | `polli update` (global installs only; npx/local get instructions) |
| Connect a coding harness to Pollinations | `polli harness <bloom\|dsh\|hermes\|opencode\|openclaw\|pi\|prime\|tgpt> on` (available adapters: `polli harness --help`) |
| Start a Linux sandbox (alpha) | `polli sandbox create` (`--timeout <seconds>` to keep it running without ssh, `0` until you pause or kill it; `pollinations-large` as the template for 4 vCPU and 8 GB; then `list`, `logs <id>`, `timeout <id> <seconds>`, `pause <id>`, `kill <id>`); the default template comes logged in, with the coding harnesses |
| ssh / scp / rsync into a sandbox | `ssh <sandbox-id>.polli`. Port forwarding (`ssh -L 3000:localhost:3000 <sandbox-id>.polli`) and VS Code Remote-SSH work. An open connection keeps the sandbox running and paid; it pauses 15–20 minutes after the last one closes (5–10 on Windows) |
| Publish a static site | `polli sites deploy ./dist --name my-app` (prints `https://my-app.pollinations.app`; then `list`, `delete <name>`) |
| Machine-readable output | append `--json` to any command |
## Setup
One-time: `polli auth login` (device-flow; creates a key with `profile`, `usage`, and `keys`). To store an existing key, run
`printf '%s' "$POLLINATIONS_API_KEY" | polli auth login --with-token`. Verify
with `polli auth status` (or `polli whoami`).
Override the stored key for a single command with `--key <key>`, or set `POLLINATIONS_API_KEY` in the environment.
Prefix any command with `POLLINATIONS_ENV=staging` to use staging; it keeps its own login, so run `POLLINATIONS_ENV=staging polli auth login` once. An exported `POLLINATIONS_API_KEY` wins over both logins.
## Recipes
### Generate an image to a file
```bash
polli gen image "a fox reading a book, studio ghibli style" --output fox.png
```
Defaults: `tongyi-mai/z-image-turbo`, 1024x1024. Without `--output` the file is `image.<ext>`, with the extension inferred from the response's `Content-Type` (`tongyi-mai/z-image-turbo` and `black-forest-labs/flux.1-schnell` return JPEG, so `image.jpg`); an explicit `--output` is used as given. Pick a different model with `--model black-forest-labs/flux.1-schnell` (see `polli models --type image`). For edits / img2img, pass one or more `--image <url>` flags — **must be public http(s) URLs**, local paths are rejected client-side. **Only models that list `"image"` in `input_modalities` actually consume the flag** — `black-forest-labs/flux.1-schnell` and `tongyi-mai/z-image-turbo` are text-only and will silently ignore `--image`. Find i2i-capable models with `polli models --type image --json | jq -r '.[] | select(.input_modalities | contains(["image"])) | .name'` (common choices: `google/gemini-2.5-flash-image`, `black-forest-labs/flux.1-kontext-pro`, `prunaai/p-image-edit`). To use a local file, upload it first with `polli upload` (see next recipe). **Img2img models may treat `--width`/`--height` as a hint** and keep the source aspect — check the output with `file`/`ffprobe`; if the aspect matters, pre-crop the source or crop afterwards.
### Upload a local file to get a public URL
```bash
URL=$(polli upload cat.png)
polli gen image "make the cat purple" --image "$URL" --output purple.png
```
`polli upload <file>` streams one raw-file request to `media.pollinations.ai` (400 MiB max; 30-day lifecycle, refreshed by GETs once the object is at least 15 days old). Each upload receives a unique id. Human mode: URL on stdout and id/size/contentType on stderr. `--json`: full upload response on stdout. The returned URL is public (no auth to fetch) and works anywhere `--image` is accepted — `gen image`, `gen video`, etc.
### Generate text
```bash
polli gen text "summarize the three laws of robotics"
```
Save to file: `--output summary.txt`. Use `--system "<msg>"` to set system prompt. For reasoning models, pass `--reasoning low|medium|high` to control reasoning effort. **Only send `--reasoning` to models where `reasoning: true`** in `polli models --type text --json` — the flag is not validated client-side, and non-reasoning models may silently accept it (openai), ignore it, or return a 400 (mistral).
### Describe an image with a vision model
```bash
URL=$(polli upload selfie.jpg)
polli gen text "turn this person into a cartoon pet in one playful sentence" --image "$URL"
```
`gen text --image <url...>` attaches one or more **public https URLs** as an OpenAI-style multimodal message — repeatable for multi-image prompts. Local paths aren't supported; run them through `polli upload` first (see the upload recipe above). **Only text models with `"image"` in `input_modalities` actually read the image** — filter with `polli models --type text --json | jq -r '.[] | select(.input_modalities | index("image")) | .name'`. Non-vision models silently ignore the attachment. Good defaults: `openai`, `gemini`, `claude`.
### Pipe stdin as context into text generation
```bash
cat README.md | polli gen text "what does this project do?"
```
stdin becomes context; the positional argument is the question.
### Interactive chat session
```bash
polli gen chat --model openai/gpt-5.4-nano --system "you are a terse assistant"
```
Slash commands inside the session: `/exit`, `/clear`, `/save <path>`.
### Text-to-speech
```bash
polli gen audio "hello world" --voice nova --output hello.mp3
echo "long script" | polli gen audio --voice nova --output out.mp3
```
Without `--voice`, the API uses the model's default voice. Voices differ per model: `polli models --type audio --voices` lists each model's voices, so pass the matching `--model` with `--voice`. Format defaults to mp3; `--format opus|aac|flac|wav` to change. Accepts stdin (same as `gen text`). Add `--play` to save and then play the audio back (handy for narration/demos). Playback starts after the file is fully written, and the command blocks until playback finishes — if you want fire-and-forget, wrap in a subshell: `( polli gen audio "..." --play & )`. Player on macOS: `afplay`; on Linux it tries `ffplay`, then `mpv`, then `mpg123` in that order.
### Generate music (elevenlabs/music-v2)
```bash
polli gen audio "lofi hip-hop beat" --model elevenlabs/music-v2 --duration 30 --instrumental --output track.mp3
```
### Generate sound effects (elevenlabs/eleven-text-to-sound-v2)
```bash
polli gen audio "thunderclap with heavy rain" --model elevenlabs/eleven-text-to-sound-v2 --duration 5 --output thunder.mp3
```
Text-to-sound-effect via ElevenLabs (aliases: `sfx`, `sound-effects`). `--duration` 0.5–30s (omit to let the model pick). Billed per second of output (~$0.004/s, capped at $0.12 for a full 30s).
### Multilingual TTS (elevenlabs/eleven-multilingual-v2)
```bash
polli gen audio "Bonjour, ceci est un test" --model elevenlabs/eleven-multilingual-v2 --voice rachel --output fr.mp3
```
Stable, lifelike TTS across 29 languages (aliases: `multilingual-v2`, `eleven-v2`) — a non-alpha alternative to the default v3.
### Estimate the cost before generating
```bash
polli gen image "a fox" --model flux --estimate
polli gen video "a spacecraft landing on mars" --model veo --duration 8 --audio --estimate
```
`--estimate` reads the public model list (`/image/models`), prints the estimated Pollen for that request and exits without generating. Per-image, per-megapixel and per-second rates give a number; token-billed models (e.g. `gpt-image-2`, `nanobanana`) print `estimate: unknown` with their rates, because the charge depends on usage the provider reports afterwards. `--json` adds `pollen` (null when unknown) and the per-rate `lines`.
### Generate video
```bash
polli gen video "a spacecraft landing on mars" --model alibaba/wan-2.2-fast --duration 5 --output mars.mp4
```
Cheapest path: `--model alibaba/wan-2.2-fast` at ~$0.01/sec, **fixed 5-second output** (any `--duration` value is ignored — you always pay for and receive 5 sec). For image-to-video, pass `--image <url>` with a **public HTTPS URL** (local file paths and 404/rate-limited hosts will fail with a server error).
**Flag support varies per model and is not enforced client-side.** `--duration`, `--aspect-ratio`, and `--audio` are forwarded to the server but may be silently ignored — verified on `wan-fast` where duration is locked to 5s, `--aspect-ratio 9:16` still returns 16:9, and `--audio` produces no audio track. Always inspect the output (`file`, `ffprobe`) before trusting a flag worked. Check `polli models --type video --json` for per-model capabilities.
**Video is not tracked by `--stats`.** `polli models --type video --stats` returns empty — the stats pipe only records text/image/audio events. To compare video models, fall back to `polli models --type video --json` and look at price/description fields. The same applies to `--type 3d`.
### Generate a 3D model
```bash
polli gen 3d "a red fox" --output fox.glb
polli gen 3d --image https://media.pollinations.ai/abc --resolution high
```
`--model` defaults to `hyper3d/rodin-2.5` for a text-only prompt and `microsoft/trellis-2` once `--image <url>` is given (public http(s), upload local files first with `polli upload`) — `trellis-2` is **image-to-3D only** and rejects a bare prompt. `--resolution low|medium|high` only affects `trellis-2`. The output extension is inferred from the response's `Content-Type`, not the model name: `nvidia/asset-harvester` returns a Gaussian Splat `.ply`, everything else returns `.glb`. `hyper3d/rodin-2.5` and `nvidia/asset-harvester` require Paid Pollen.
### Generate embeddings
```bash
polli gen embeddings "first text" "second text" --model google/gemini-embedding-2
printf 'first\nsecond\n' | polli gen embeddings # one input per stdin line
```
Prints one JSON array per input, in input order, one per line (pipe/`jq`-friendly). `--dimensions <n>` (128-4096), `--task-type` (Gemini retrieval hint), and `--input-type query|document` (Cohere) are optional. `--json` prints the full response including `usage`.
### Change or isolate a voice
```bash
polli gen voice-change talk.mp3 --voice nova --format wav
polli gen isolate interview.mp4
```
`voice-change` re-speaks a **local** audio file in another voice (preset name or ElevenLabs voice ID) — default output `voice.<format>`. `isolate` strips music/background noise from local audio **or video**, keeping only speech — default output `isolated.mp3`. Both upload the file as multipart form data; ElevenLabs requires **at least 4.6 seconds** of audio for isolation, shorter clips fail with the API's `audio_too_short` error.
### Speech with character-level timestamps
```bash
polli gen audio "Hello world" --timestamps
```
Saves the audio as usual (`speech.mp3` by default) and appends `.json` to its path for the `alignment`/`normalized_alignment` character timings. Only `elevenlabs/eleven-v3`, `elevenlabs/eleven-flash-v2.5`, and `elevenlabs/eleven-multilingual-v2` support this — other models fail with the API's error message.
### Transcribe audio to text
```bash
polli gen transcribe recording.mp3 --language en
```
Models: `openai/whisper-large-v3` (default), `elevenlabs/scribe-v2`, `assemblyai/universal-2`, `assemblyai/universal-3.5-pro`. Accepts common audio formats (mp3, wav, m4a, flac, ogg); non-audio input (e.g. a `.txt` file) returns a clear `400 invalid_request_error: extension "txt" not supported` — no need to pre-validate with `file`. Default output is the plain transcript on stdout as a single line (pipe-friendly). Use `--json` for structured output: **whisper** and **AssemblyAI** return timing data when requested through the API; **scribe** returns only `{text: "..."}` — use whisper or AssemblyAI if you need timing data. `--language <ISO-639-1>` (e.g. `en`, `fr`) is an optional hint that can improve accuracy for non-English or accented speech.
### Discover models
```bash
polli models --type text # text models only
polli models flux # search name, aliases, title, description, publisher
polli models --source community # official or community only
polli models --reliability all # also community models failing health checks
polli models --type audio --voices # voices per model
polli models --type image --verbose # with publisher, context length, pricing
polli models --stats # health + avg latency + err% (60m default)
polli models --stats --window 5 # last 5 minutes only
```
Use `--stats` before choosing a model. **Caveat**: the `err%` column counts **5xx only** — a model can show `0.0%` while having massive 4xx rates (auth, validation, etc.). For the full picture use `--stats --json` and read `errors_4xx`, `errors_5xx`, `latency_p95_ms`.
**Pricing fields are per-token, not per-request.** `completionImageTokens: 0.000008` means each output image-token costs that much — a single 1024x1024 image from `openai/gpt-image-1-mini` lands at ~$0.008, not $0.000008. Flat-priced image models (`black-forest-labs/flux.1-schnell`, `tongyi-mai/z-image-turbo`) expose `completionImageTokens` as the whole-image price because they emit exactly one "token" per image. When in doubt, make one call and read the true cost from `polli usage --history --limit 5 --json`.
### Check usage and balance
```bash
polli usage # current pollen balance
polli usage --history # recent individual requests
polli usage --daily # daily cost summary
polli usage --daily --key polli-harness-claude --days 1 # cost of one harness key for the last day (`--model`, `--csv` filter/export both views; `--key` is repeatable)
polli earnings # developer earnings total + per-entity breakdown (default 30d)
polli earnings --days 7 # rolling window
polli quests # your quests + claim state (open/claimable/claimed/closed/coming)
polli quests --claimable # only rewards ready to claim
```
**History is eventually consistent** — a request you just made may not appear for 30–60s. When matching costs to freshly-generated media, use `--limit 50` and filter by timestamp, and retry if the expected entry is missing. `polli usage --json` returns `{"pollen": <number>}` — the current balance only; use `--history --json` or `--daily --json` for cost breakdowns. Those print a JSON array of the API usage records (numeric `cost_usd`, `api_key_id`, available per-modality token fields), not the table columns.
### Manage my-models
```bash
polli my-models list
polli my-models models --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY"
polli my-models create --name my-model --title "My Model" --api chat_completions --url https://api.example.com/v1/chat/completions --bearer-token "$UPSTREAM_KEY" --upstream-model gpt-4.1-mini --required-safety privacy,secrets,sexual,violence,shield
polli my-models create --name my-image --title "My Image" --modality image --image-pricing request --completion-image-price 0.01 --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --upstream-model flux
polli my-models update <id> --description "Updated description"
polli my-models update <id> --paid-only # only accept Paid Pollen; --no-paid-only reverts
polli my-models update <id> --required-safety privacy,secrets,sexual,violence,shield
polli my-models delete <id>
```
`my-models` manages owned community text, image, and transcription models. Any account can create private models; `communityEndpointsAllowed: true` is required only to publish them. API keys require `account:keys`. Use `account:usage` for narrow read-only usage and `polli quests`; use both permissions when a client needs both read-only account state and admin operations. Quest claiming is dashboard-only; `polli quests` is read-only and account-aware.
### Register an image my-model
```bash
polli my-models test --modality image --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --model image-v1
polli my-models create --name my-image --title "My Image" --modality image --image-pricing request --completion-image-price 0.01 --input-modalities text,image --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --upstream-model image-v1
```
Test before creating. The probe reports the pricing mode it detected and the input modalities it found, including whether the endpoint accepts image edits; pass those back as `--input-modalities text,image` to advertise edit support. `polli my-models list` shows them in the `inputs` column.
Two billing modes: `--image-pricing request` charges `--completion-image-price` per generated image, while `--image-pricing tokens` bills returned token usage per 1M through `--prompt-text-price`, `--prompt-image-price`, and `--completion-image-price`.
Prices only apply to `--visibility public` models. A private model is owner-only and always free, so every price flag above is stored as `0` until you publish — and making a published model private clears its prices again.
`--modality` is fixed at creation — `update` cannot change it.
### Manage agents
```bash
polli agents list
polli agents get <id>
polli agents create --config agent.json --name my-agent --title "My Agent"
polli agents create --config code-agent.json
polli agents update <id> --config agent.json
polli agents sync <id>
polli agents delete <id>
```
Prompt-agent config contains `systemPrompt`, `baseModel`, and optional `mcpServers` (add `composio` to act in the caller's own accounts, such as a GitHub commit; callers connect apps at https://enter.pollinations.ai/account#connectors); create also requires `--name` and `--title`. Code-agent config contains `type: "code_agent"` and a public GitHub `repository` with `agent.ts` at its root; its model ID, title, and description come from GitHub. Use server IDs from the MCP catalog. Updates are partial: send only the fields to change; the rest keep their values. `sync` deploys the latest GitHub revision of a code agent.
Creating an agent also creates its callable model listing. Managed agents are text-only and free, with no fallbacks or per-user RPM. Deleting the agent also deletes its model listing. See [Publish an Agent](https://github.com/pollinations/pollinations/blob/main/BUILD_YOUR_OWN_AGENT.md).
### Publish a static site
```bash
npm run build
polli sites deploy ./dist --name my-app # → https://my-app.pollinations.app
polli sites list
polli sites delete my-app
```
Publishes a folder of static files with an `index.html`; unknown paths serve `index.html`, so single-page apps route on the client. Deploying the same name again replaces the site and uploads only changed files. Names are 3–32 lowercase letters, digits and hyphens, starting with a letter; the first deploy claims the name. Limits: 5 sites per account, 200 MB and 1,000 files per site, 25 MiB per file. Dotfiles and `node_modules` are not uploaded. Sites are public: never put an API key in them. To call Pollinations from a site, let visitors sign in with their own Pollen (see [Connect User Wallets](https://gen.pollinations.ai/docs/llm.txt?section=byop)). Share the URL the command prints rather than composing one from the name.
### Manage API keys
```bash
polli keys list # list all keys on the account
polli keys info # details about the CURRENTLY AUTHENTICATED key only (takes no id)
polli keys create --name "my-bot" --type secret --budget 1000 --permissions profile usage # scoped key
polli keys create --name "my-app" --type publishable --redirect-uri https://app.example/callback --earnings
polli keys create --name "server" --models black-forest-labs/flux.1-schnell tongyi-mai/z-image-turbo # only these two models
polli keys update <id> --models text black-forest-labs/flux.1-schnell # every text model plus FLUX.1 Schnell
polli keys revoke <id> # id comes from `keys list --json`
```
`--models` takes categories (`text`, `image`, `video`, `audio`, `3d`, `embedding`, `realtime`, `decision`) and model IDs from `polli models`. A category includes models added later; a model ID allows only that model.
`--permissions <perms...>` scopes what the new key can do on the account (e.g. `profile usage` lets it call `polli --key <new> usage`). **Without `--permissions`, new scoped keys can generate media but cannot read account state** — `polli --key <new> usage` will 403. Include `keys` to let the new key create, list, and revoke keys itself. Existing keys with `account:keys` can manage my-models where that invite-only feature is enabled, but still need `account:usage` for read-only account state. Publishable app keys default developer earnings off; pass `--earnings` to enable them. To inspect a specific key other than the current one, use `polli keys list --json | jq '.[] | select(.id == "<id>")'`. `keys info` is intentionally scoped to the caller's own key.
### Connect a coding harness
Polli defaults to `openai/gpt-6-sol`; `--model <id>` overrides it. Bloom is key-only and keeps its own model selection.
```bash
polli harness --help # supported harnesses
polli harness bloom on # create a dedicated key for Bloom CLI
polli harness dsh on # login if needed, mint key "polli-harness-dsh", write provider + default model
polli harness dsh on --model moonshotai/kimi-k2.6 # use the model ID from `polli models`
polli harness dsh on --no-mcp # configure the provider and skill without MCP tools
polli harness dsh off # restore the config backed up before "on"
polli harness hermes on # login if needed, mint key "polli-harness-hermes", add provider + Polli skill
polli harness hermes on --model deepseek/deepseek-v4-flash # use the model ID from `polli models`
polli harness hermes off # restore the config backed up before "on"
polli harness opencode on # add the Pollinations provider (OpenCode 1.x and 2.x)
polli harness opencode off # remove the provider setup and stored key
polli harness pi on # login if needed, mint key "polli-harness-pi", configure Pi with Pollinations
polli harness pi on --model moonshotai/kimi-k2.6 # use the model ID from `polli models`
polli harness pi off # restore the Pi config backed up before "on"
polli harness openclaw on # login if needed, mint key "polli-harness-openclaw", add provider + Polli skill
polli harness openclaw off # remove the Pollinations provider, key, and skill
polli harness tgpt on # use tgpt's Pollinations provider with a dedicated key
polli harness tgpt off # restore tgpt's previous configuration
```
Each adapter checks that its harness can be launched before login, key creation, or configuration. DSH's official launch uses `npx`, so its adapter checks for `npx`; Bloom, Hermes Agent, OpenCode, OpenClaw, Pi, and tgpt require their installed commands.
Bloom already uses Pollinations and only needs a dedicated key in `$BLOOM_HOME/.env` (default `~/.bloom/.env`). tgpt's existing Pollinations provider is selected in `~/.config/tgpt/config.conf` with a dedicated key and model. The DSH adapter globally configures the Pollinations provider, hosted Pollinations MCP, and this skill under `$DSH_HOME` (default `~/.dsh`). OpenCode adds a `pollinations` provider (read by both 1.x and 2.x) and stores its dedicated key in the provider's options. OpenClaw adds a `pollinations` provider to `~/.openclaw/openclaw.json`, stores a dedicated key in `env.vars`, and installs this skill under `~/.openclaw/skills/polli/`. Pi writes `~/.pi/agent/models.json`, `auth.json`, and `settings.json`, and installs this skill under `~/.pi/agent/skills/polli/`. Guide: `polli docs` section "Coding Harnesses".
### Read API docs
```bash
polli docs # full llm.txt reference
polli docs /v1/chat/completions # filter to one endpoint
polli docs --open # open in browser
```
## Output contract
- **Default (human mode):** varies by command — most emit `key: value` pairs or tab-separated tables with a header row. Exceptions: `gen text` prints the full response to stdout; `gen transcribe` prints the transcript as plain text; `gen chat` runs an interactive REPL. Status/progress messages go to stderr, so pipes stay clean.
- **`--json`:** every command emits machine-parseable JSON to stdout; all human messages go to stderr. **Always prefer `--json` when piping into `jq` or parsing** — it's the only shape with a stable contract.
- **Exit codes:** 0 on success, non-zero on auth failure, rate limit, network error, or invalid args. Error messages go to stderr.
## Agent operating rules
1. **Run `polli auth status` (or `polli whoami`) first** if you don't know whether the user is logged in. Fail fast with a clear "run `polli auth login`" message if not.
2. **Prefer `--json`** whenever you'll parse the output. Never grep human-formatted tables.
3. **Don't hardcode model IDs.** Fetch the live list with `polli models --type <type>`. Model availability changes.
4. **Before picking a model for production use, check `polli models --stats`.** Rule of thumb for "healthy": `err%` ≤ 5, `avg` latency in a reasonable range for the modality (standard text <5s, image <10s, video <60s), and `requests` high enough to be statistically meaningful (ignore rows with <10 requests — noise). **Filter by capability first, then optimize by health** — e.g. for a reasoning task, narrow to models where `reasoning: true` (via `polli models --type text --json`), *then* cross-reference against `--stats` output. The healthiest model overall may not support the capability you need. **Reasoning models are inherently slower — expect 5–50s, not <5s**; when picking among them, prioritize low `err%` and request count over raw latency, and compare latency only within the reasoning-capable subset.
5. **Always pass `--output <path>`** for `gen image`, `gen audio`, `gen video` — otherwise the file lands in the current directory with a default name.
6. **For stdin-as-context** on `gen text`, pipe the context and pass the question as the positional argument: `cat file | polli gen text "question about the file"`.
7. **For exact flag lists, run `polli <cmd> --help` or `polli gen <cmd> --help`.** This skill's recipes cover the common path; the CLI's own help is always the source of truth.
8. **Use `polli docs [endpoint]` over guessing API shapes.** It prints the canonical `llm.txt` reference from the live API.
## Common pitfalls
- Forgetting `--output` on binary generators (image/audio/video) — the file goes to a default path, which may not be what the user wants.
- Using `polli gen text --json` expecting OpenAI chat-completions shape — the CLI's `--json` wraps its own structure. Use `polli docs /v1/chat/completions` to see the raw API shape if you need it.
- Running commands without auth — `polli auth status` / `polli whoami` tells you who you're logged in as and your balance in one call.
- **`gen text` streams to a TTY, buffers when piped.** The default now auto-detects — a human at the terminal sees tokens tick in, a pipe/redirect gets the full response once. Force either mode with `--stream` or `--no-stream`. For scripts and chains like `polli gen text … | polli gen audio …`, you don't need to do anything; buffering happens automatically.
- **Translating a `polli` workflow into a browser app.** `gen.pollinations.ai` requires a bearer token for generation requests, so a plain client-side `fetch` with no auth returns 401 unless it is served from cache. Mint a scoped key with `polli keys create` and proxy via your own backend.
- **Backgrounded `polli gen` can fail silently** — no output file, empty log, no error (a safety rejection is an explicit 400). Run in the foreground; if backgrounded, check the `--output` file exists and retry once in the foreground before calling it failed.
- **Content-safety 400s aren't only about violence.** Body-focused action phrasing can trip a sexual-content category on some edit models. Rephrase the benign intent neutrally (e.g. sport framing) and retry with a new seed.
---
name: polli
description: Generate images, text, audio, video, and transcribe speech via the Pollinations API using the polli CLI. Use when asked to generate media, call pollinations.ai, check pollen balance, list models, manage API keys, inspect quests, manage agents or my-models, publish a static site, or run polli commands.
allowed-tools: Bash(polli *)
---
# polli — Pollinations CLI
Thin wrapper around `gen.pollinations.ai`. Generates images, text, audio, video; transcribes speech; manages API keys, usage, quests, agents, and invite-only my-models.
If `polli` is not installed, run `npm i -g @pollinations/cli@latest` (provides the `polli` binary).
## When to use this skill
- User asks to **generate an image / text / audio / video** via pollinations
- User mentions **polli, pollinations, pollen, pollinations.ai**
- User wants to **transcribe speech** or run TTS
- User asks about their **pollen balance, usage, or API keys**
- User wants to **browse or filter available models**
- User wants to inspect **quests** or manage invite-only **my-models**
- User wants to create or update a hosted prompt **agent**
- User wants to **publish a website or web app** they built
For agent-assisted login, use `polli --json auth login --no-browser`. Read stderr while the command runs and show the user the verification URL and user code so they can review access. On approval, stdout contains one JSON result: `{"authenticated":true}`. Tokens are stored locally and never included in that result.
## Quick reference
| Intent | Command |
|---|---|
| Log in once | `polli auth login` |
| Agent-assisted login | `polli --json auth login --no-browser` |
| Store an existing key | `printf '%s' "$POLLINATIONS_API_KEY" \| polli auth login --with-token` |
| Generate image | `polli gen image "<prompt>" --output out.png` |
| Generate text | `polli gen text "<prompt>"` |
| Text with stdin as context | `echo "<ctx>" \| polli gen text "<question>"` |
| Describe an image (vision) | `polli gen text "what is this?" --image <url>` |
| One-shot TTS | `polli gen audio "<text>" --output speech.mp3` |
| Speak out loud | `polli gen audio "<text>" --play` (uses `afplay` on macOS; `ffplay`/`mpv`/`mpg123` on Linux) |
| Generate video | `polli gen video "<prompt>" --output out.mp4` |
| Generate a 3D model | `polli gen 3d "<prompt>" --output out.glb` (or `--image <url>` for image-only models) |
| Embed text | `polli gen embeddings "<text>" ["<text2>" ...]` (one vector per line; also reads stdin) |
| Change a voice | `polli gen voice-change talk.mp3 --voice nova` |
| Isolate speech | `polli gen isolate interview.mp4` (strips music/noise) |
| Speech + character timings | `polli gen audio "<text>" --timestamps` (also writes `speech.mp3.json`) |
| Transcribe audio | `polli gen transcribe path/to.mp3` |
| Upload a local file | `polli upload path/to.png` (prints public URL) |
| List all models | `polli models` |
| Search models | `polli models <query>` (`--source official\|community`, `--reliability all`) |
| Discover voices | `polli models --type audio --voices` (one line per model) |
| Filter models by type | `polli models --type image` (text, decision, image, audio, video, 3d, embedding, realtime) |
| Model health + latency | `polli models --stats` (default 60m, `--window <min>`) |
| Check balance | `polli usage` |
| Developer earnings | `polli earnings` (`--days <n>`) |
| List your quests + claim state | `polli quests` (filters: `--open --claimable --claimed --coming-soon`) |
| Manage prompt agents | `polli agents list` |
| Manage invite-only community models | `polli my-models list` |
| Update the CLI | `polli update` (global installs only; npx/local get instructions) |
| Connect a coding harness to Pollinations | `polli harness <bloom\|dsh\|hermes\|opencode\|openclaw\|pi\|prime\|tgpt> on` (available adapters: `polli harness --help`) |
| Start a Linux sandbox (alpha) | `polli sandbox create` (`--timeout <seconds>` to keep it running without ssh, `0` until you pause or kill it; `pollinations-large` as the template for 4 vCPU and 8 GB; then `list`, `logs <id>`, `timeout <id> <seconds>`, `pause <id>`, `kill <id>`); the default template comes logged in, with the coding harnesses |
| ssh / scp / rsync into a sandbox | `ssh <sandbox-id>.polli`. Port forwarding (`ssh -L 3000:localhost:3000 <sandbox-id>.polli`) and VS Code Remote-SSH work. An open connection keeps the sandbox running and paid; it pauses 15–20 minutes after the last one closes (5–10 on Windows) |
| Publish a static site | `polli sites deploy ./dist --name my-app` (prints `https://my-app.pollinations.app`; then `list`, `delete <name>`) |
| Machine-readable output | append `--json` to any command |
## Setup
One-time: `polli auth login` (device-flow; creates a key with `profile`, `usage`, and `keys`). To store an existing key, run
`printf '%s' "$POLLINATIONS_API_KEY" | polli auth login --with-token`. Verify
with `polli auth status` (or `polli whoami`).
Override the stored key for a single command with `--key <key>`, or set `POLLINATIONS_API_KEY` in the environment.
Prefix any command with `POLLINATIONS_ENV=staging` to use staging; it keeps its own login, so run `POLLINATIONS_ENV=staging polli auth login` once. An exported `POLLINATIONS_API_KEY` wins over both logins.
## Recipes
### Generate an image to a file
```bash
polli gen image "a fox reading a book, studio ghibli style" --output fox.png
```
Defaults: `tongyi-mai/z-image-turbo`, 1024x1024. Without `--output` the file is `image.<ext>`, with the extension inferred from the response's `Content-Type` (`tongyi-mai/z-image-turbo` and `black-forest-labs/flux.1-schnell` return JPEG, so `image.jpg`); an explicit `--output` is used as given. Pick a different model with `--model black-forest-labs/flux.1-schnell` (see `polli models --type image`). For edits / img2img, pass one or more `--image <url>` flags — **must be public http(s) URLs**, local paths are rejected client-side. **Only models that list `"image"` in `input_modalities` actually consume the flag** — `black-forest-labs/flux.1-schnell` and `tongyi-mai/z-image-turbo` are text-only and will silently ignore `--image`. Find i2i-capable models with `polli models --type image --json | jq -r '.[] | select(.input_modalities | contains(["image"])) | .name'` (common choices: `google/gemini-2.5-flash-image`, `black-forest-labs/flux.1-kontext-pro`, `prunaai/p-image-edit`). To use a local file, upload it first with `polli upload` (see next recipe). **Img2img models may treat `--width`/`--height` as a hint** and keep the source aspect — check the output with `file`/`ffprobe`; if the aspect matters, pre-crop the source or crop afterwards.
### Upload a local file to get a public URL
```bash
URL=$(polli upload cat.png)
polli gen image "make the cat purple" --image "$URL" --output purple.png
```
`polli upload <file>` streams one raw-file request to `media.pollinations.ai` (400 MiB max; 30-day lifecycle, refreshed by GETs once the object is at least 15 days old). Each upload receives a unique id. Human mode: URL on stdout and id/size/contentType on stderr. `--json`: full upload response on stdout. The returned URL is public (no auth to fetch) and works anywhere `--image` is accepted — `gen image`, `gen video`, etc.
### Generate text
```bash
polli gen text "summarize the three laws of robotics"
```
Save to file: `--output summary.txt`. Use `--system "<msg>"` to set system prompt. For reasoning models, pass `--reasoning low|medium|high` to control reasoning effort. **Only send `--reasoning` to models where `reasoning: true`** in `polli models --type text --json` — the flag is not validated client-side, and non-reasoning models may silently accept it (openai), ignore it, or return a 400 (mistral).
### Describe an image with a vision model
```bash
URL=$(polli upload selfie.jpg)
polli gen text "turn this person into a cartoon pet in one playful sentence" --image "$URL"
```
`gen text --image <url...>` attaches one or more **public https URLs** as an OpenAI-style multimodal message — repeatable for multi-image prompts. Local paths aren't supported; run them through `polli upload` first (see the upload recipe above). **Only text models with `"image"` in `input_modalities` actually read the image** — filter with `polli models --type text --json | jq -r '.[] | select(.input_modalities | index("image")) | .name'`. Non-vision models silently ignore the attachment. Good defaults: `openai`, `gemini`, `claude`.
### Pipe stdin as context into text generation
```bash
cat README.md | polli gen text "what does this project do?"
```
stdin becomes context; the positional argument is the question.
### Interactive chat session
```bash
polli gen chat --model openai/gpt-5.4-nano --system "you are a terse assistant"
```
Slash commands inside the session: `/exit`, `/clear`, `/save <path>`.
### Text-to-speech
```bash
polli gen audio "hello world" --voice nova --output hello.mp3
echo "long script" | polli gen audio --voice nova --output out.mp3
```
Without `--voice`, the API uses the model's default voice. Voices differ per model: `polli models --type audio --voices` lists each model's voices, so pass the matching `--model` with `--voice`. Format defaults to mp3; `--format opus|aac|flac|wav` to change. Accepts stdin (same as `gen text`). Add `--play` to save and then play the audio back (handy for narration/demos). Playback starts after the file is fully written, and the command blocks until playback finishes — if you want fire-and-forget, wrap in a subshell: `( polli gen audio "..." --play & )`. Player on macOS: `afplay`; on Linux it tries `ffplay`, then `mpv`, then `mpg123` in that order.
### Generate music (elevenlabs/music-v2)
```bash
polli gen audio "lofi hip-hop beat" --model elevenlabs/music-v2 --duration 30 --instrumental --output track.mp3
```
### Generate sound effects (elevenlabs/eleven-text-to-sound-v2)
```bash
polli gen audio "thunderclap with heavy rain" --model elevenlabs/eleven-text-to-sound-v2 --duration 5 --output thunder.mp3
```
Text-to-sound-effect via ElevenLabs (aliases: `sfx`, `sound-effects`). `--duration` 0.5–30s (omit to let the model pick). Billed per second of output (~$0.004/s, capped at $0.12 for a full 30s).
### Multilingual TTS (elevenlabs/eleven-multilingual-v2)
```bash
polli gen audio "Bonjour, ceci est un test" --model elevenlabs/eleven-multilingual-v2 --voice rachel --output fr.mp3
```
Stable, lifelike TTS across 29 languages (aliases: `multilingual-v2`, `eleven-v2`) — a non-alpha alternative to the default v3.
### Estimate the cost before generating
```bash
polli gen image "a fox" --model flux --estimate
polli gen video "a spacecraft landing on mars" --model veo --duration 8 --audio --estimate
```
`--estimate` reads the public model list (`/image/models`), prints the estimated Pollen for that request and exits without generating. Per-image, per-megapixel and per-second rates give a number; token-billed models (e.g. `gpt-image-2`, `nanobanana`) print `estimate: unknown` with their rates, because the charge depends on usage the provider reports afterwards. `--json` adds `pollen` (null when unknown) and the per-rate `lines`.
### Generate video
```bash
polli gen video "a spacecraft landing on mars" --model alibaba/wan-2.2-fast --duration 5 --output mars.mp4
```
Cheapest path: `--model alibaba/wan-2.2-fast` at ~$0.01/sec, **fixed 5-second output** (any `--duration` value is ignored — you always pay for and receive 5 sec). For image-to-video, pass `--image <url>` with a **public HTTPS URL** (local file paths and 404/rate-limited hosts will fail with a server error).
**Flag support varies per model and is not enforced client-side.** `--duration`, `--aspect-ratio`, and `--audio` are forwarded to the server but may be silently ignored — verified on `wan-fast` where duration is locked to 5s, `--aspect-ratio 9:16` still returns 16:9, and `--audio` produces no audio track. Always inspect the output (`file`, `ffprobe`) before trusting a flag worked. Check `polli models --type video --json` for per-model capabilities.
**Video is not tracked by `--stats`.** `polli models --type video --stats` returns empty — the stats pipe only records text/image/audio events. To compare video models, fall back to `polli models --type video --json` and look at price/description fields. The same applies to `--type 3d`.
### Generate a 3D model
```bash
polli gen 3d "a red fox" --output fox.glb
polli gen 3d --image https://media.pollinations.ai/abc --resolution high
```
`--model` defaults to `hyper3d/rodin-2.5` for a text-only prompt and `microsoft/trellis-2` once `--image <url>` is given (public http(s), upload local files first with `polli upload`) — `trellis-2` is **image-to-3D only** and rejects a bare prompt. `--resolution low|medium|high` only affects `trellis-2`. The output extension is inferred from the response's `Content-Type`, not the model name: `nvidia/asset-harvester` returns a Gaussian Splat `.ply`, everything else returns `.glb`. `hyper3d/rodin-2.5` and `nvidia/asset-harvester` require Paid Pollen.
### Generate embeddings
```bash
polli gen embeddings "first text" "second text" --model google/gemini-embedding-2
printf 'first\nsecond\n' | polli gen embeddings # one input per stdin line
```
Prints one JSON array per input, in input order, one per line (pipe/`jq`-friendly). `--dimensions <n>` (128-4096), `--task-type` (Gemini retrieval hint), and `--input-type query|document` (Cohere) are optional. `--json` prints the full response including `usage`.
### Change or isolate a voice
```bash
polli gen voice-change talk.mp3 --voice nova --format wav
polli gen isolate interview.mp4
```
`voice-change` re-speaks a **local** audio file in another voice (preset name or ElevenLabs voice ID) — default output `voice.<format>`. `isolate` strips music/background noise from local audio **or video**, keeping only speech — default output `isolated.mp3`. Both upload the file as multipart form data; ElevenLabs requires **at least 4.6 seconds** of audio for isolation, shorter clips fail with the API's `audio_too_short` error.
### Speech with character-level timestamps
```bash
polli gen audio "Hello world" --timestamps
```
Saves the audio as usual (`speech.mp3` by default) and appends `.json` to its path for the `alignment`/`normalized_alignment` character timings. Only `elevenlabs/eleven-v3`, `elevenlabs/eleven-flash-v2.5`, and `elevenlabs/eleven-multilingual-v2` support this — other models fail with the API's error message.
### Transcribe audio to text
```bash
polli gen transcribe recording.mp3 --language en
```
Models: `openai/whisper-large-v3` (default), `elevenlabs/scribe-v2`, `assemblyai/universal-2`, `assemblyai/universal-3.5-pro`. Accepts common audio formats (mp3, wav, m4a, flac, ogg); non-audio input (e.g. a `.txt` file) returns a clear `400 invalid_request_error: extension "txt" not supported` — no need to pre-validate with `file`. Default output is the plain transcript on stdout as a single line (pipe-friendly). Use `--json` for structured output: **whisper** and **AssemblyAI** return timing data when requested through the API; **scribe** returns only `{text: "..."}` — use whisper or AssemblyAI if you need timing data. `--language <ISO-639-1>` (e.g. `en`, `fr`) is an optional hint that can improve accuracy for non-English or accented speech.
### Discover models
```bash
polli models --type text # text models only
polli models flux # search name, aliases, title, description, publisher
polli models --source community # official or community only
polli models --reliability all # also community models failing health checks
polli models --type audio --voices # voices per model
polli models --type image --verbose # with publisher, context length, pricing
polli models --stats # health + avg latency + err% (60m default)
polli models --stats --window 5 # last 5 minutes only
```
Use `--stats` before choosing a model. **Caveat**: the `err%` column counts **5xx only** — a model can show `0.0%` while having massive 4xx rates (auth, validation, etc.). For the full picture use `--stats --json` and read `errors_4xx`, `errors_5xx`, `latency_p95_ms`.
**Pricing fields are per-token, not per-request.** `completionImageTokens: 0.000008` means each output image-token costs that much — a single 1024x1024 image from `openai/gpt-image-1-mini` lands at ~$0.008, not $0.000008. Flat-priced image models (`black-forest-labs/flux.1-schnell`, `tongyi-mai/z-image-turbo`) expose `completionImageTokens` as the whole-image price because they emit exactly one "token" per image. When in doubt, make one call and read the true cost from `polli usage --history --limit 5 --json`.
### Check usage and balance
```bash
polli usage # current pollen balance
polli usage --history # recent individual requests
polli usage --daily # daily cost summary
polli usage --daily --key polli-harness-claude --days 1 # cost of one harness key for the last day (`--model`, `--csv` filter/export both views; `--key` is repeatable)
polli earnings # developer earnings total + per-entity breakdown (default 30d)
polli earnings --days 7 # rolling window
polli quests # your quests + claim state (open/claimable/claimed/closed/coming)
polli quests --claimable # only rewards ready to claim
```
**History is eventually consistent** — a request you just made may not appear for 30–60s. When matching costs to freshly-generated media, use `--limit 50` and filter by timestamp, and retry if the expected entry is missing. `polli usage --json` returns `{"pollen": <number>}` — the current balance only; use `--history --json` or `--daily --json` for cost breakdowns. Those print a JSON array of the API usage records (numeric `cost_usd`, `api_key_id`, available per-modality token fields), not the table columns.
### Manage my-models
```bash
polli my-models list
polli my-models models --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY"
polli my-models create --name my-model --title "My Model" --api chat_completions --url https://api.example.com/v1/chat/completions --bearer-token "$UPSTREAM_KEY" --upstream-model gpt-4.1-mini --required-safety privacy,secrets,sexual,violence,shield
polli my-models create --name my-image --title "My Image" --modality image --image-pricing request --completion-image-price 0.01 --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --upstream-model flux
polli my-models update <id> --description "Updated description"
polli my-models update <id> --paid-only # only accept Paid Pollen; --no-paid-only reverts
polli my-models update <id> --required-safety privacy,secrets,sexual,violence,shield
polli my-models delete <id>
```
`my-models` manages owned community text, image, and transcription models. Any account can create private models; `communityEndpointsAllowed: true` is required only to publish them. API keys require `account:keys`. Use `account:usage` for narrow read-only usage and `polli quests`; use both permissions when a client needs both read-only account state and admin operations. Quest claiming is dashboard-only; `polli quests` is read-only and account-aware.
### Register an image my-model
```bash
polli my-models test --modality image --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --model image-v1
polli my-models create --name my-image --title "My Image" --modality image --image-pricing request --completion-image-price 0.01 --input-modalities text,image --base-url https://api.example.com/v1 --bearer-token "$UPSTREAM_KEY" --upstream-model image-v1
```
Test before creating. The probe reports the pricing mode it detected and the input modalities it found, including whether the endpoint accepts image edits; pass those back as `--input-modalities text,image` to advertise edit support. `polli my-models list` shows them in the `inputs` column.
Two billing modes: `--image-pricing request` charges `--completion-image-price` per generated image, while `--image-pricing tokens` bills returned token usage per 1M through `--prompt-text-price`, `--prompt-image-price`, and `--completion-image-price`.
Prices only apply to `--visibility public` models. A private model is owner-only and always free, so every price flag above is stored as `0` until you publish — and making a published model private clears its prices again.
`--modality` is fixed at creation — `update` cannot change it.
### Manage agents
```bash
polli agents list
polli agents get <id>
polli agents create --config agent.json --name my-agent --title "My Agent"
polli agents create --config code-agent.json
polli agents update <id> --config agent.json
polli agents sync <id>
polli agents delete <id>
```
Prompt-agent config contains `systemPrompt`, `baseModel`, and optional `mcpServers` (add `composio` to act in the caller's own accounts, such as a GitHub commit; callers connect apps at https://enter.pollinations.ai/account#connectors); create also requires `--name` and `--title`. Code-agent config contains `type: "code_agent"` and a public GitHub `repository` with `agent.ts` at its root; its model ID, title, and description come from GitHub. Use server IDs from the MCP catalog. Updates are partial: send only the fields to change; the rest keep their values. `sync` deploys the latest GitHub revision of a code agent.
Creating an agent also creates its callable model listing. Managed agents are text-only and free, with no fallbacks or per-user RPM. Deleting the agent also deletes its model listing. See [Publish an Agent](https://github.com/pollinations/pollinations/blob/main/BUILD_YOUR_OWN_AGENT.md).
### Publish a static site
```bash
npm run build
polli sites deploy ./dist --name my-app # → https://my-app.pollinations.app
polli sites list
polli sites delete my-app
```
Publishes a folder of static files with an `index.html`; unknown paths serve `index.html`, so single-page apps route on the client. Deploying the same name again replaces the site and uploads only changed files. Names are 3–32 lowercase letters, digits and hyphens, starting with a letter; the first deploy claims the name. Limits: 5 sites per account, 200 MB and 1,000 files per site, 25 MiB per file. Dotfiles and `node_modules` are not uploaded. Sites are public: never put an API key in them. To call Pollinations from a site, let visitors sign in with their own Pollen (see [Connect User Wallets](https://gen.pollinations.ai/docs/llm.txt?section=byop)). Share the URL the command prints rather than composing one from the name.
### Manage API keys
```bash
polli keys list # list all keys on the account
polli keys info # details about the CURRENTLY AUTHENTICATED key only (takes no id)
polli keys create --name "my-bot" --type secret --budget 1000 --permissions profile usage # scoped key
polli keys create --name "my-app" --type publishable --redirect-uri https://app.example/callback --earnings
polli keys create --name "server" --models black-forest-labs/flux.1-schnell tongyi-mai/z-image-turbo # only these two models
polli keys update <id> --models text black-forest-labs/flux.1-schnell # every text model plus FLUX.1 Schnell
polli keys revoke <id> # id comes from `keys list --json`
```
`--models` takes categories (`text`, `image`, `video`, `audio`, `3d`, `embedding`, `realtime`, `decision`) and model IDs from `polli models`. A category includes models added later; a model ID allows only that model.
`--permissions <perms...>` scopes what the new key can do on the account (e.g. `profile usage` lets it call `polli --key <new> usage`). **Without `--permissions`, new scoped keys can generate media but cannot read account state** — `polli --key <new> usage` will 403. Include `keys` to let the new key create, list, and revoke keys itself. Existing keys with `account:keys` can manage my-models where that invite-only feature is enabled, but still need `account:usage` for read-only account state. Publishable app keys default developer earnings off; pass `--earnings` to enable them. To inspect a specific key other than the current one, use `polli keys list --json | jq '.[] | select(.id == "<id>")'`. `keys info` is intentionally scoped to the caller's own key.
### Connect a coding harness
Polli defaults to `openai/gpt-6-sol`; `--model <id>` overrides it. Bloom is key-only and keeps its own model selection.
```bash
polli harness --help # supported harnesses
polli harness bloom on # create a dedicated key for Bloom CLI
polli harness dsh on # login if needed, mint key "polli-harness-dsh", write provider + default model
polli harness dsh on --model moonshotai/kimi-k2.6 # use the model ID from `polli models`
polli harness dsh on --no-mcp # configure the provider and skill without MCP tools
polli harness dsh off # restore the config backed up before "on"
polli harness hermes on # login if needed, mint key "polli-harness-hermes", add provider + Polli skill
polli harness hermes on --model deepseek/deepseek-v4-flash # use the model ID from `polli models`
polli harness hermes off # restore the config backed up before "on"
polli harness opencode on # add the Pollinations provider (OpenCode 1.x and 2.x)
polli harness opencode off # remove the provider setup and stored key
polli harness pi on # login if needed, mint key "polli-harness-pi", configure Pi with Pollinations
polli harness pi on --model moonshotai/kimi-k2.6 # use the model ID from `polli models`
polli harness pi off # restore the Pi config backed up before "on"
polli harness openclaw on # login if needed, mint key "polli-harness-openclaw", add provider + Polli skill
polli harness openclaw off # remove the Pollinations provider, key, and skill
polli harness tgpt on # use tgpt's Pollinations provider with a dedicated key
polli harness tgpt off # restore tgpt's previous configuration
```
Each adapter checks that its harness can be launched before login, key creation, or configuration. DSH's official launch uses `npx`, so its adapter checks for `npx`; Bloom, Hermes Agent, OpenCode, OpenClaw, Pi, and tgpt require their installed commands.
Bloom already uses Pollinations and only needs a dedicated key in `$BLOOM_HOME/.env` (default `~/.bloom/.env`). tgpt's existing Pollinations provider is selected in `~/.config/tgpt/config.conf` with a dedicated key and model. The DSH adapter globally configures the Pollinations provider, hosted Pollinations MCP, and this skill under `$DSH_HOME` (default `~/.dsh`). OpenCode adds a `pollinations` provider (read by both 1.x and 2.x) and stores its dedicated key in the provider's options. OpenClaw adds a `pollinations` provider to `~/.openclaw/openclaw.json`, stores a dedicated key in `env.vars`, and installs this skill under `~/.openclaw/skills/polli/`. Pi writes `~/.pi/agent/models.json`, `auth.json`, and `settings.json`, and installs this skill under `~/.pi/agent/skills/polli/`. Guide: `polli docs` section "Coding Harnesses".
### Read API docs
```bash
polli docs # full llm.txt reference
polli docs /v1/chat/completions # filter to one endpoint
polli docs --open # open in browser
```
## Output contract
- **Default (human mode):** varies by command — most emit `key: value` pairs or tab-separated tables with a header row. Exceptions: `gen text` prints the full response to stdout; `gen transcribe` prints the transcript as plain text; `gen chat` runs an interactive REPL. Status/progress messages go to stderr, so pipes stay clean.
- **`--json`:** every command emits machine-parseable JSON to stdout; all human messages go to stderr. **Always prefer `--json` when piping into `jq` or parsing** — it's the only shape with a stable contract.
- **Exit codes:** 0 on success, non-zero on auth failure, rate limit, network error, or invalid args. Error messages go to stderr.
## Agent operating rules
1. **Run `polli auth status` (or `polli whoami`) first** if you don't know whether the user is logged in. Fail fast with a clear "run `polli auth login`" message if not.
2. **Prefer `--json`** whenever you'll parse the output. Never grep human-formatted tables.
3. **Don't hardcode model IDs.** Fetch the live list with `polli models --type <type>`. Model availability changes.
4. **Before picking a model for production use, check `polli models --stats`.** Rule of thumb for "healthy": `err%` ≤ 5, `avg` latency in a reasonable range for the modality (standard text <5s, image <10s, video <60s), and `requests` high enough to be statistically meaningful (ignore rows with <10 requests — noise). **Filter by capability first, then optimize by health** — e.g. for a reasoning task, narrow to models where `reasoning: true` (via `polli models --type text --json`), *then* cross-reference against `--stats` output. The healthiest model overall may not support the capability you need. **Reasoning models are inherently slower — expect 5–50s, not <5s**; when picking among them, prioritize low `err%` and request count over raw latency, and compare latency only within the reasoning-capable subset.
5. **Always pass `--output <path>`** for `gen image`, `gen audio`, `gen video` — otherwise the file lands in the current directory with a default name.
6. **For stdin-as-context** on `gen text`, pipe the context and pass the question as the positional argument: `cat file | polli gen text "question about the file"`.
7. **For exact flag lists, run `polli <cmd> --help` or `polli gen <cmd> --help`.** This skill's recipes cover the common path; the CLI's own help is always the source of truth.
8. **Use `polli docs [endpoint]` over guessing API shapes.** It prints the canonical `llm.txt` reference from the live API.
## Common pitfalls
- Forgetting `--output` on binary generators (image/audio/video) — the file goes to a default path, which may not be what the user wants.
- Using `polli gen text --json` expecting OpenAI chat-completions shape — the CLI's `--json` wraps its own structure. Use `polli docs /v1/chat/completions` to see the raw API shape if you need it.
- Running commands without auth — `polli auth status` / `polli whoami` tells you who you're logged in as and your balance in one call.
- **`gen text` streams to a TTY, buffers when piped.** The default now auto-detects — a human at the terminal sees tokens tick in, a pipe/redirect gets the full response once. Force either mode with `--stream` or `--no-stream`. For scripts and chains like `polli gen text … | polli gen audio …`, you don't need to do anything; buffering happens automatically.
- **Translating a `polli` workflow into a browser app.** `gen.pollinations.ai` requires a bearer token for generation requests, so a plain client-side `fetch` with no auth returns 401 unless it is served from cache. Mint a scoped key with `polli keys create` and proxy via your own backend.
- **Backgrounded `polli gen` can fail silently** — no output file, empty log, no error (a safety rejection is an explicit 400). Run in the foreground; if backgrounded, check the `--output` file exists and retry once in the foreground before calling it failed.
- **Content-safety 400s aren't only about violence.** Body-focused action phrasing can trip a sexual-content category on some edit models. Rephrase the benign intent neutrally (e.g. sport framing) and retry with a new seed.
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Includes source scripts; review them before use. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.