Skip to content

keryx portrait

Stylise reference photo(s) into the risograph avatar via the image provider (Gemini image-to-image) — a port of gen-portrait.py. Resolves a portrait theme for the prompt.

keryx portrait --ref photo1.jpg [--ref photo2.jpg ...] [--theme <kw>] [--model <id>] [--n N] [--out portrait]
Flag Meaning Default
--ref a reference photo (repeatable) — (≥1 required)
--theme portrait theme (the avatar prompt) configured portrait default
--model force a specific image model id config providers.gemini.model, else the fallback chain
--n number of variants 1
--out output path prefix → <out>-<i>.png portrait
--dry-run estimate what this would cost and generate nothing false

Credential: GEMINI_API_KEY (env). Used for the blog logo / social avatar, not the per-post pipeline. Reference photos are sent as image-to-image conditioning; their MIME type is detected from content. Feed several real photos so the model triangulates the likeness; gemini-3-pro-image (via --model or providers.gemini.model) gives the best results.

keryx portrait --ref me1.jpg --ref me2.jpg --n 3 --model gemini-3-pro-image

A provider can return fewer variants than --n asked for. keryx re-asks for the shortfall (up to three extra attempts); if it still comes up short the run warns, naming requested and written counts, and writes what it got with exit status 0 — the same behaviour as cover.

Provider-selected via providers.image — see Providers.

Costing a run before making it

--dry-run prices the run and generates nothing — no provider call, no files, no spend. The estimate is an upper bound: an unchanged request is served from the content cache without spending (R-GLOBAL-9), so a real run may cost nothing. When the estimate crosses spend.confirm_above.*, the dry run says so.

--output json gives the same figures structured, which is how an assistant driving keryx over MCP asks what something costs before committing to it.