Potaco is a Go CLI for image generation and editing via multiple AI image providers. Connect to OpenAI, fal, Vercel AI Gateway, or any OpenAI-compatible API via the custom provider.
Warning
This project is still in beta. Therefore, critical breakages or bugs are to be expected. Use at your own risk, and please report any issues you encounter.
- Multi-provider support for OpenAI, fal, Vercel AI Gateway, and custom OpenAI-compatible endpoints
- Encrypted credentials stored locally
- Auth management with
auth add/remove/listcommands - Provider switching with
potaco use <provider> - Model discovery via provider APIs
- Generate images from text prompts with size, quality, seed, and guidance control
- Edit existing images with inpainting (mask-based) and outpainting (canvas extension)
- Status and models commands to inspect current state and available models
- Interactive TUI with interactive forms for auth, model selection, and provider switching
- Info inspect image metadata (dimensions, format, file size, color model)
- Retry with exponential backoff on rate-limit and server errors
- JSON output for scripting and piping
- Dry-run mode to validate requests without calling the API
- Non-interactive mode with
--non-interactiveflag for agents and automated terminal execution
curl -fsSL https://github.com/ncxton/potaco/releases/latest/download/install.sh | shThe installer detects your platform, downloads the matching binary, verifies the checksum, and installs to ~/.local/bin.
curl -fsSL https://github.com/ncxton/potaco/releases/latest/download/install.sh | POTACO_NON_INTERACTIVE=1 shNon-interactive installer mode is plain output for agents and automated terminal execution, not a polished scripting API.
Download the archive for your platform from the releases page, extract, and move the potaco binary to a directory in your PATH.
Supported platforms:
- Linux x86_64 (amd64)
- Linux ARM64 (arm64)
- macOS Intel (darwin/amd64)
- macOS Apple Silicon (darwin/arm64)
# Connect a provider (interactive TUI prompts for key, verification, and model)
potaco auth add openai
# Or non-interactive:
potaco auth add openai --api-key sk-xxx
# Generate an image
potaco gen --prompt "a red fox in a forest"
# Switch to another provider
potaco auth add fal --api-key <fal-key>
potaco use fal
# List or pick available models from the active provider
potaco models # interactive picker (persists the selected model)
potaco models list # static list of models
potaco models list openai # static list for a specific provider
# Check current status
potaco statusGenerate new images from a text prompt.
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--prompt, -p |
string | yes | Text description of the desired image(s) | |
--model |
string | no | from config | Model to use (e.g., gpt-image-2) |
--size |
string | no | 1024x1024 |
Image dimensions (WxH) |
--quality |
string | no | auto |
Image quality (low, medium, high, or auto) |
--n |
int | no | 1 |
Number of images to generate |
--seed |
int | no | 0 |
Reproducibility seed |
--guidance-scale |
float | no | 0 |
Guidance scale |
--negative-prompt |
string | no | Negative prompt | |
--response-format |
string | no | b64_json |
Response format (url or b64_json) |
--output, -o |
string | no | auto | Output file path (auto: potaco-YYYYMMDD-HHMMSS.png) |
--output-format |
string | no | png |
Output format (png or jpeg) |
--stdout |
bool | no | false |
Pipe raw image bytes to stdout |
--dry-run |
bool | no | false |
Print request payload without calling API |
--json |
bool | no | false |
Output JSON metadata to stdout |
--provider |
string | no | from config | Override active provider |
--base-url |
string | no | from provider | Override API base URL |
--api-key |
string | no | from credentials | Override API key |
--retries |
int | no | 2 |
Max retry attempts |
--timeout |
string | no | 120 |
Request timeout in seconds |
Examples:
potaco gen --prompt "a red fox in a forest"
potaco gen --prompt "a cityscape at night" --size 1536x1024 --quality high --n 2
potaco gen --prompt "portrait of a woman" --seed 42 --json
potaco gen --prompt "test" --dry-run
potaco gen --prompt "test" --provider fal --api-key <key> --dry-runEdit an existing image with inpainting (mask-based editing) or outpainting (canvas extension).
| Flag | Type | Required | Default | Description |
|---|---|---|---|---|
--prompt, -p |
string | yes | Text description of the edit | |
--image |
string | yes | Path to source image file | |
--mask |
string | no | Path to mask image file (transparent=edit, opaque=keep) | |
--mask-rect |
string | no | Rectangular mask: x,y,w,h in pixels |
|
--mask-circle |
string | no | Circular mask: x,y,r in pixels |
|
--extend |
string | no | Outpaint: top=N,bottom=N,left=N,right=N or all=N |
|
--model |
string | no | from config | Model to use |
--size |
string | no | 1024x1024 |
Image dimensions (WxH) |
--n |
int | no | 1 |
Number of images to generate |
--response-format |
string | no | b64_json |
Response format (url or b64_json) |
--output, -o |
string | no | auto | Output file path |
--output-format |
string | no | png |
Output format (png or jpeg) |
--stdout |
bool | no | false |
Pipe raw image bytes to stdout |
--dry-run |
bool | no | false |
Print request payload without calling API |
--provider |
string | no | from config | Override active provider |
--base-url |
string | no | from provider | Override API base URL |
--api-key |
string | no | from credentials | Override API key |
--retries |
int | no | 2 |
Max retry attempts |
--timeout |
string | no | 120 |
Request timeout in seconds |
Examples:
potaco edit --prompt "make it look like a painting" --image photo.png
potaco edit --prompt "remove the person" --image photo.png --mask mask.png
potaco edit --prompt "replace with a tree" --image photo.png --mask-rect 100,200,300,300
potaco edit --prompt "extend the landscape" --image photo.png --extend right=256,bottom=256edit only runs when the selected model is configured as edit capable. Interactive model selection asks this after you pick a model. For non-interactive setup, set it yourself after confirming provider support:
potaco config set model.edit true
potaco config set providers.openai.models.gpt-image-2.edit trueConnect providers, add API keys, and manage credentials. Credentials are encrypted at rest.
potaco auth add openai # interactive TUI flow
potaco auth add openai --api-key sk-xxx # non-interactive
potaco auth add fal --api-key <key> # connect fal
potaco auth add vercel --api-key <key> # connect Vercel AI Gateway
potaco auth add custom --api-key <key> --base-url <url> # connect any OpenAI-compatible endpoint
potaco auth add openrouter --type openai-compatible --api-key <key> --base-url <url> # named custom endpoint
potaco auth add staging-openai --type openai --api-key <key> --base-url <url> # named provider using a built-in adapter type
potaco auth remove openai # disconnect a provider
potaco auth list # list connected providers
potaco auth list --json # JSON outputSwitch the active provider and optionally change the model.
potaco use openai # switch to openai
potaco use fal # switch to fal
potaco use openai --model gpt-image-2 # switch and set modelWhen run interactively with no arguments, a TUI picker appears.
Display the active provider, model, config and credential paths, and connected providers.
potaco status # text output
potaco status --json # JSON outputDiscover models from the active provider or a specified provider. By default, the command launches an interactive picker that persists the selected model to config and asks whether it can edit images. In non-interactive mode it falls back to a static list.
potaco models # interactive picker for the active provider
potaco models openai # interactive picker for a specific provider
potaco models --non-interactive # static list for the active provider
potaco models list # static list for the active provider
potaco models list openai # static list for a specific provider
potaco models --json --non-interactive # JSON output (static list)Use potaco models list when you only want to see available model IDs without changing the active model. Model discovery does not configure or display generation/edit capability; generation is assumed available, and edit capability is user-configured.
Manage per-provider settings stored in ~/.potaco/config.yaml. API keys are stored separately in the encrypted credential file.
potaco config set model gpt-image-2 # change active provider model
potaco config set providers.vercel.model openai/gpt-image-2 # set a provider model
potaco config set model.edit true # mark active provider model edit capable
potaco config set providers.openai.models.gpt-image-2.edit true # mark a specific model edit capable
potaco config set base_url https://api.example.com/v1 # set active provider base URL
potaco config set retries 3 # set active provider retries
potaco config set timeout 120 # set active provider timeout in seconds
potaco config set auto_update false # disable automatic update prompts
potaco config show # display current configPrint metadata about an image file.
potaco info output.png
potaco info output.png --jsonPrint the current binary version and check for updates. Interactive commands check for updates automatically by default; disable that with potaco config set auto_update false.
potaco version
potaco version --json
potaco --versionDownload and run the installer for the latest release.
potaco update # update if newer version available
potaco update --force # force update even if already latestRemove the potaco binary. Interactive uninstall asks whether to remove local configuration.
potaco uninstall # interactive removal
potaco uninstall --yes # skip confirmation promptsDisable interactive TUI flows and automatic update prompts. Useful for agents and automated terminal execution, not a polished scripting API. Can also be set via the POTACO_NON_INTERACTIVE=1 environment variable.
potaco --non-interactive auth add openai --api-key sk-xxx
POTACO_NON_INTERACTIVE=1 potaco modelsPotaco stores configuration in ~/.potaco/config.yaml and encrypted credentials in ~/.potaco/credentials.enc.
Config file format (~/.potaco/config.yaml):
active_provider: openai
active_model: gpt-image-2
auto_update: true
providers:
openai:
model: gpt-image-2
base_url: https://api.openai.com/v1
retries: 3
timeout: 120
fal:
model: fal-ai/flux/dev
base_url: https://fal.run
retries: 3
timeout: 120The base_url field is optional for built-in provider names (openai, fal, vercel) and overrides their preset URL. It is required for any other provider name, including custom and aliases that use a built-in adapter type.
API keys are stored separately in ~/.potaco/credentials.enc, encrypted with a machine-derived key.
Update check metadata is stored separately in ~/.potaco/.potaco.json.
Environment variables:
| Variable | Description |
|---|---|
POTACO_PROVIDER |
Active provider name (e.g., openai, fal, vercel, custom) |
POTACO_API_KEY |
API key for the active provider |
POTACO_MODEL |
Default model for the active provider |
POTACO_BASE_URL |
Override the provider's base URL (required for custom and provider aliases) |
POTACO_RETRIES |
Max retry attempts |
POTACO_TIMEOUT |
Request timeout in seconds (e.g., 120) |
POTACO_NON_INTERACTIVE |
Set to 1 to disable TUI flows for agents and automated terminal execution; not a polished scripting API |
Supported providers:
The known provider names below ship with preset base URLs. Any other auth name, including custom and aliases using a built-in adapter type, requires --base-url or base_url in config.
| Provider | Auth Type | Edit Support |
|---|---|---|
openai |
Bearer | Yes |
fal |
Key | Yes |
vercel |
Bearer | No |
See CONTRIBUTING.md for development setup, coding standards, and the pull request process.
Every PR runs: build, go vet, gofmt, staticcheck, gocyclo (complexity threshold 30), go mod tidy, coverage, gitleaks (secret scanning), and tests.
sh scripts/install-hooks.sh # Install gofmt, vet, tidy, and test hooksSee .env.example for a template of all supported environment variables.
MIT - Copyright (c) 2026 ncxton
