Skip to content

Command-line interface

The imagegen-bridge binary uses the same normalized contract, layered configuration, provider registry, runtime limits, and artifact verification as the Rust facade and HTTP server. It never requires an OPENAI_API_KEY for the Codex providers; they inherit the existing Codex OAuth login.

Build the binary from a local checkout with:

cargo build --release -p imagegen-bridge-cli
./target/release/imagegen-bridge setup
./target/release/imagegen-bridge doctor

Guided setup and diagnostics

setup is idempotent and safe to rerun. It detects the Codex executable and ChatGPT OAuth login, chooses XDG-compatible config/state/data locations, previews all changes, writes configuration atomically, protects the state directory, and initializes the session database. It does not copy OAuth tokens.

imagegen-bridge setup --dry-run
imagegen-bridge setup
imagegen-bridge setup --yes --non-interactive --json
imagegen-bridge setup \
  --config ./bridge.toml \
  --state-root ./data/state \
  --output-root ./data/artifacts \
  --yes --non-interactive

Interactive mutations require confirmation. Machine output modes never prompt; use --yes to apply their displayed plan. A missing or incomplete installation can be repaired by rerunning the same command. No paid request occurs unless --live-probe is present, and that probe requires a separate confirmation (or an explicit --yes).

doctor checks the bridge version, config file and schema, Codex version, protected OAuth file, storage permissions, SQLite migration version, configured port, provider readiness, and capability discovery:

imagegen-bridge doctor
imagegen-bridge doctor --provider codex-responses --json
imagegen-bridge doctor --live-probe
imagegen-bridge doctor --live-probe --yes --non-interactive --json

The normal doctor path is non-generating. The live probe produces exactly one image, verifies it through the ordinary runtime, returns dimensions/format and elapsed time, and does not retain image bytes because it requests metadata output.

Updates and rollback

An explicit check is read-only and works without bridge configuration:

imagegen-bridge update check
imagegen-bridge update check --json

For a standalone binary, preview the target and backup location before applying the update. The release archive must match its entry in the release SHA256SUMS; replacement is atomic and retains one previous binary beside the executable.

imagegen-bridge update install --dry-run
imagegen-bridge update install --yes
imagegen-bridge update rollback --dry-run
imagegen-bridge update rollback --yes

On Windows, update check and dry-run planning are supported, but replacing a running executable is left to the verified release archive installer. Linux and macOS standalone binaries support the atomic self-update path.

Self-replacement is intentionally refused inside a container. Run the Docker update from the host instead; it updates only IMAGEGEN_BRIDGE_IMAGE in the selected environment file, pulls and recreates only the bridge service, and restores the previous pin if Compose fails.

imagegen-bridge update docker \
  --compose-file compose.package.yaml \
  --env-file .env \
  --dry-run
imagegen-bridge update docker \
  --compose-file compose.package.yaml \
  --env-file .env \
  --yes

For a no-502 planned handoff with exactly one OAuth-active slot, use compose.handoff.yaml and add --active-passive. The updater places the OAuth-sterile gateway in bounded hold, stops the old slot, readiness-gates the new slot, and rolls back automatically on failure.

After successful interactive CLI commands, a background check may print one short update notice to the terminal at most once per day. It is skipped for JSON/plain output, quiet mode, CI, server/dashboard processes, redirected stderr, and network failures. The notice includes the installed/latest version and the appropriate dry-run next step: standalone install or Docker-host update. It sends no telemetry, caches only public release metadata with 0600 permissions, and can be disabled with IMAGEGEN_BRIDGE_NO_UPDATE_CHECK=1.

Generation and editing

Every normalized request field is available either through a complete native JSON request or ergonomic flags:

imagegen-bridge generate \
  "A red origami fox on warm gray" \
  --quality auto \
  --size auto \
  --output illustrations/fox.png \
  --collision suffix

imagegen-bridge edit \
  "Change the jacket to blue" \
  --image ./portrait.png \
  --reference ./palette.png \
  --response-format artifact

imagegen-bridge generate --request request.json --json
imagegen-bridge generate --request - --json < request.json
imagegen-bridge generate --prompt - --dry-run --json < prompt.txt
imagegen-bridge generate "a red-haired woman" --dry-run --json

imagegen-bridge generate \
  "Four distinct editorial variations of a red-haired woman" \
  --count 4 \
  --failure-policy best_effort \
  --output-dir batches/red-haired-woman

--request is lossless and exclusive: it cannot be mixed with prompt, input, or parameter flags. --dry-run validates and prints the normalized request without opening artifact/session storage or starting Codex.

Reusable presets retain the complete request configuration but never retain input-image bytes, masks, reference images, or idempotency keys:

imagegen-bridge preset create portrait-high --from request.json \
  --description "High-quality portrait defaults"
imagegen-bridge preset list --json
imagegen-bridge preset get portrait-high --json
imagegen-bridge generate "A red-haired woman" --preset portrait-high
imagegen-bridge preset update portrait-high --from updated-template.json
imagegen-bridge preset delete portrait-high --dry-run
imagegen-bridge preset delete portrait-high --force

--from accepts either an ImagePresetTemplate JSON object or a complete native ImageRequest; the latter is reduced to reusable fields. An explicit generation/edit prompt replaces the stored prompt, and explicit CLI flags replace only their matching preset fields. Generate and edit presets cannot be applied to the opposite operation. Presets use the configured durable SQLite state shared with the API and dashboard. Deletion requires --force, while --dry-run is non-mutating.

--count N requests multiple outputs. A provider may return them natively or the bridge may fan out into independent upstream calls; inspect providers capabilities --json and its batching field for the exact behavior. Isolated Codex app-server batches can run concurrently. --session-key and --thread-id batches are intentionally sequential so turns on one conversation remain ordered. Use --batch-execution sequential for one upstream fan-out call at a time or --batch-execution parallel to require concurrent fan-out. With the default max_parallel_outputs = "auto", every requested output starts concurrently; set a positive integer in provider configuration to impose your own ceiling. auto is the default and becomes sequential for conversational sessions.

Human-readable CLI failures print every structured recovery suggestion on its own suggestion: line. JSON mode exposes the same ordered suggestions array, alongside code, retryable, provider, request correlation and safe details.

-o, --output FILE selects an exact filename and is valid only when n=1. --output-dir DIR retains generated UUID filenames inside a per-call directory. Relative paths are interpreted below artifacts.root; an absolute CLI path is accepted only when it resolves lexically below that root. Directories and filenames use a portable ASCII contract and cannot contain hidden components, backslashes, traversal, or an extension that disagrees with --format. Publication never overwrites: --collision error is the default, while --collision suffix atomically selects name-2.png, name-3.png, and so on. Supplying either path option changes the default b64_json response to artifact; an explicitly incompatible response mode fails validation.

--metadata sidecar selects artifact delivery when no response format was explicitly chosen and opts into a portable metadata-<artifact-id>.json file in the same directory as each image. It contains the original/effective prompt, negative prompt, operation summary without input paths or bytes, requested/effective parameters, normalization records, revised prompt, provider/model, ordered fallback attempts, usage, session, timings, warnings, and independently verified image properties. The response exposes its relative metadata_name; cleanup verifies and removes the owned image and sidecar together. Sidecars are off by default because prompt and session content may be sensitive.

--metadata embedded writes a bounded XMP record directly into PNG, JPEG, or WebP bytes without re-encoding pixels. It can remain in the default b64_json response or accompany artifact/URL delivery; metadata-only output is rejected. The final response checksum covers the image with XMP included. --metadata sidecar_and_embedded writes both forms and implicitly selects artifact delivery. Embedded records include prompt and session content and are therefore just as privacy-sensitive as sidecars. Combined prompt text above 12 KiB is rejected before provider work. Oversized response-only fields are named in omitted_fields rather than silently truncated. The Rust artifact library exposes extract_embedded_metadata with explicit image limits for verified, bounded extraction.

--preview selects artifact output when no response format was explicitly chosen and renders PNG through Kitty graphics or supported image formats through the iTerm2 inline protocol (also used by WezTerm). Unsupported formats, terminals, and redirected stdout receive a clear fallback message without turning a successful generation into a failure. Preview is rejected with --json/machine output so control sequences can never corrupt the wire stream. --open launches each artifact or bridge URL with the platform viewer (xdg-open, open, or Windows start). Viewer launch failures are reported as command failures; artifact paths are canonicalized and checked against the configured root first.

Advanced flags include --negative-prompt, --negative-prompt-mode, --revised-prompt, --aspect-ratio, --resolution, --compression, --background, --transparency, --chroma-key, both chroma thresholds, --no-despill, --fallback, --fallback-policy, --batch-execution, --moderation, --partial-images, --failure-policy, --input-fidelity, --action, --compatibility, --output, --output-dir, --collision, --metadata, --open, --preview, --session, --session-key, --thread-id, --idempotency-key, and --timeout-ms. Availability is provider/model-specific; inspect it before requesting strict parameters:

imagegen-bridge providers list --json
imagegen-bridge providers capabilities --json
imagegen-bridge providers readiness --json

Image-generation parameters covered by provider capabilities fail before provider work when strict and unsupported. --compatibility normalize or best_effort permits only the explicit fallbacks reported in normalizations. The native contract also accepts an opaque --user field. Both current Codex transports reject it before provider work because neither upstream path proves that it consumes this attribution; the field is never silently discarded, including in best_effort mode.

--failure-policy fail_fast is the default for multiple outputs. --failure-policy best_effort keeps successful outputs and reports failed indices in failures; this is separate from provider compatibility --compatibility best_effort.

--background transparent --transparency auto prefers native alpha and otherwise uses the bridge's local chroma-key processor. The processor chooses a key color from the prompt, asks the model for a uniform keyed background, samples the actual output border, creates a soft alpha matte, despills edges, and rejects a missing/pathological matte. native requires provider support; chroma_key forces local processing. PNG and WebP preserve alpha. The offline equivalent is background remove INPUT --output OUTPUT --key auto.

--fallback PROVIDER[:MODEL] is repeatable and ordered. The default on_unavailable policy reroutes only unavailable/unsupported conditions. on_error also permits errors with a known upstream outcome. Safety refusals, permission errors, cancellation, session errors, and unknown outcomes never reroute. Fallback requires an isolated session and successful responses expose the full route trace in attempts.

--input-fidelity low|high requires at least one source/reference image. gpt-image-2 accepts only high because its inputs are always processed at high fidelity. --action edit likewise requires image context, while --action generate cannot be combined with the native edit operation. Masks are rejected during capability negotiation on both current Codex transports.

Sessions and server

--session-key NAME implies persistent mode and reuses the same app-server thread on later calls. --thread-id ID implies explicit-thread mode.

imagegen-bridge session get gallery --json
imagegen-bridge session delete gallery --dry-run --json
imagegen-bridge session delete gallery --force --json
imagegen-bridge serve
imagegen-bridge serve --bind 127.0.0.1:9000
imagegen-bridge gateway --state-file /coord/active-slot
imagegen-bridge dashboard
imagegen-bridge dashboard --no-open
imagegen-bridge dashboard --attach-only --json

Session deletion and artifact cleanup require --force; their --dry-run forms are non-mutating. serve reports its listener on stderr and stops gracefully on Ctrl-C/SIGINT. With durable jobs enabled it also reports the embedded dashboard URL, normally http://127.0.0.1:8787/dashboard.

Artifact ownership repair is also explicit and bounded. Stop the bridge before applying it, audit first, then confirm the same conservative pass:

imagegen-bridge artifacts repair --dry-run --json
imagegen-bridge artifacts repair --force --json

Repair removes a valid ownership record only when its artifact is absent. It may also remove an unchanged owned sidecar attached to that missing artifact, or clear a sidecar reference when the artifact is valid but the sidecar is absent. Changed artifacts, changed sidecars, invalid markers, symlinks, and unowned files are reported as skipped and never modified.

dashboard is the local UI launcher. It first probes the configured loopback address and, when that endpoint is an Imagegen Bridge dashboard, prints its connection details and exits. Otherwise it starts the same API and embedded UI in the foreground, choosing an available loopback port if the configured port is occupied by an unrelated process. An explicit --bind IP:PORT never falls back and accepts loopback IPs only. --attach-only prohibits startup; --no-open prohibits browser launch; --open requests it even without an interactive terminal. Automatic browser opening occurs only for human output on an interactive terminal.

JSON connection output has stable mode, url, api_base_url, bind, authentication, and opened fields. A launcher-owned pid is present only when the command started the server. Attached authentication is reported as unknown because the public HTML shell intentionally cannot disclose server policy. Plain mode emits one key=value per line and never includes secrets.

Configuration, diagnostics, and schemas

Configuration precedence is:

defaults < --config TOML < IMAGEGEN_BRIDGE__* environment < --set/--unset

When --config is omitted, the CLI checks ./imagegen-bridge.toml first and then the XDG user configuration ($XDG_CONFIG_HOME/imagegen-bridge/config.toml, falling back to ~/.config/imagegen-bridge/config.toml).

imagegen-bridge config check --json
imagegen-bridge config show --json
imagegen-bridge config origins --json
imagegen-bridge --set runtime.default_timeout_ms=600000 config check
imagegen-bridge auth-doctor --json
imagegen-bridge auth-doctor --provider codex-app-server --json
imagegen-bridge schema --kind json-schema
imagegen-bridge schema --kind openapi
imagegen-bridge schema --kind openapi --check schemas/imagegen-bridge-v1.openapi.json
imagegen-bridge completions bash
imagegen-bridge man --output imagegen-bridge.1

config check is non-mutating. config show prints credential environment variable names, never their resolved values. config origins prints field paths and source keys without values. auth-doctor performs non-generating provider checks.

Output and exit contract

Primary results go to stdout. Diagnostics and server status go to stderr. --json emits stable JSON; --plain emits compact line-oriented output; human output never prints base64 bodies. JSON base64 output is refused when stdout is an interactive terminal unless --allow-inline is explicit.

Local agents can request a separate, explicit path-bearing envelope:

imagegen-bridge --json --local-artifact-paths generate \
  --prompt "a paper fox" --output-dir agent --metadata sidecar

This flag is accepted only for non-dry-run generate and edit commands and requires JSON output. The envelope contains the ordinary response under response plus artifacts[] entries with verified canonical path and optional metadata_path. It rejects non-artifact output, missing names, oversized files, non-files, changed artifact checksums, and any canonical path outside artifacts.root. These host paths are intentionally CLI-only and must not be relayed through a remote API or public log.

Exit Meaning
0 Success
2 CLI syntax, invalid request, configuration, or idempotency conflict
3 Authentication, permission, or safety rejection
4 Input, artifact, or session failure
5 Rate limit or bounded-capacity overload
6 Unsupported capability, upstream, or protocol failure
70 Unexpected internal failure
124 Request deadline exceeded
130 Cancelled or interrupted operation

stdin, request files, configuration files, multipart bodies, RPC messages, and generated artifacts all retain their configured byte/count/time bounds.