{"id":50417687,"url":"https://github.com/walker1211/codex-imgen","last_synced_at":"2026-05-31T07:00:57.926Z","repository":{"id":359382382,"uuid":"1231042446","full_name":"walker1211/codex-imgen","owner":"walker1211","description":"Local-first CLI and async job service for Codex CLI $imagegen.","archived":false,"fork":false,"pushed_at":"2026-05-30T17:39:59.000Z","size":558,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-30T19:15:53.417Z","etag":null,"topics":["cli","codex","codex-cli","go","golang","image-generation","image-to-image","local-first","text-to-image"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/walker1211.png","metadata":{"files":{"readme":"README.en.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-06T15:10:24.000Z","updated_at":"2026-05-30T17:40:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/walker1211/codex-imgen","commit_stats":null,"previous_names":["walker1211/codex-imgen"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/walker1211/codex-imgen","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/walker1211%2Fcodex-imgen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/walker1211%2Fcodex-imgen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/walker1211%2Fcodex-imgen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/walker1211%2Fcodex-imgen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/walker1211","download_url":"https://codeload.github.com/walker1211/codex-imgen/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/walker1211%2Fcodex-imgen/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33722156,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","codex","codex-cli","go","golang","image-generation","image-to-image","local-first","text-to-image"],"created_at":"2026-05-31T07:00:55.021Z","updated_at":"2026-05-31T07:00:57.910Z","avatar_url":"https://github.com/walker1211.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# codex-imgen\n\n[中文](./README.zh-CN.md) | [English](./README.en.md)\n\n`codex-imgen` is a local-first Go CLI and async job service for Codex CLI `$imagegen`. It turns Codex image generation into a scriptable workflow for text-to-image, image-to-image, batch-style generation, job tracking, and agent/service integration.\n\n`codex-imgen` is an independent community tool and is not affiliated with OpenAI.\n\n## Why codex-imgen?\n\nCodex CLI already has image generation. `codex-imgen` focuses on the engineering layer around it:\n\n- Run text-to-image and image-to-image from a simple local CLI\n- Use local reference images with repeated `--image` flags\n- Submit async jobs and query them later with `status`, `get`, `list`, and `cancel`\n- Control candidate generation with `--count` and `--concurrency`\n- Subscribe to job-scoped WebSocket events from local tools and agents\n- Check OpenClaw/TG original-file delivery contracts and skill sync drift\n- Keep structured settings in `configs/config.yaml` and secrets in `.env`\n\nIf you only need one image once, native `codex exec` is enough. If you need repeatable generation, batching, job tracking, or local integration, use `codex-imgen`.\n\n## Comparison\n\n| Need | Native `codex exec` | `codex-imgen` |\n|---|---:|---:|\n| One-off prompt | yes | yes |\n| Simple CLI UX | limited | yes |\n| Local reference images | manual | yes |\n| Batch count/concurrency | manual | yes |\n| Async job queue | no | yes |\n| Status/list/cancel | no | yes |\n| WebSocket events | no | yes |\n| Agent/service integration | manual | yes |\n| Local YAML config | no | yes |\n\n## Installation\n\n#### Option 1: Download a release archive\n\nDownload the archive for your OS/arch from [GitHub Releases](https://github.com/walker1211/codex-imgen/releases), then unpack it:\n\n```bash\ntar -xzf codex-imgen_\u003ctag\u003e_\u003cos\u003e_\u003carch\u003e.tar.gz\ncd codex-imgen_\u003ctag\u003e_\u003cos\u003e_\u003carch\u003e\ncp configs/config.example.yaml configs/config.yaml\n# Optional, only needed when email secrets are enabled:\ncp .example.env .env\n./imgen --help\n```\n\nOn Windows, run `imgen.exe --help`.\n\nRelease archives include the `imgen` and `skill-sync` binaries, `configs/config.example.yaml`, `.example.env`, README files, and `LICENSE`.\n\n#### Option 2: Build from source\n\nRequires Go and a logged-in Codex CLI.\n\n```bash\ngit clone https://github.com/walker1211/codex-imgen.git\ncd codex-imgen\ncp configs/config.example.yaml configs/config.yaml\n# Optional, only needed when email secrets are enabled:\ncp .example.env .env\nbash ./build.sh\n./imgen --help\n```\n\nThe source-build commands above assume a Unix-like shell. On Windows, built binaries are named `imgen.exe` and `skill-sync.exe`.\n\nFill in `configs/config.yaml` before using service mode, custom backend settings, or email notifications. Put SMTP auth secrets in `.env` only.\n\nNote: the binary reads `configs/config.yaml` from the current working directory. Adding the binary to `PATH` does not remove that requirement.\n\n## Skill Sync\n\n`.claude/skills/imgen/` is the skill source; `.openclaw/skills/imgen/` is the repository OpenClaw mirror; `~/.claude/skills/imgen/`, `~/.openclaw/workspace/skills/imgen/`, and `~/.codex/skills/imgen/` are local install artifacts.\n\nCheck whether local installs match the repository sources:\n\n```bash\ngo run ./cmd/skill-sync --check\n```\n\nCopy repository sources into local Claude, OpenClaw, and Codex installs, and update the repository OpenClaw mirror:\n\n```bash\ngo run ./cmd/skill-sync --apply\n```\n\nYou can also build first with `bash ./build.sh` and then use the local binary:\n\n```bash\n./skill-sync --check\n./skill-sync --apply\n```\n\nThe default behavior is drift checking only; local skill install directories are overwritten only when `--apply` is passed explicitly.\n\n## OpenClaw doctor\n\nCheck whether the local OpenClaw setup satisfies the imgen / Telegram original-file delivery contract:\n\n```bash\n./imgen doctor openclaw\n```\n\nThis read-only command checks the `image_generate` deny rules, main agent `message` exposure, Telegram direct `NO_REPLY` silence, OpenClaw `message send --force-document` support, OpenClaw imgen skill installation/sync state, the `IMGEN_DELIVERY_DIR` / `forceDocument` / `asDocument` call contract, the synchronous CLI JSON success contract, and whether local `backend.delivery_dir` is under an OpenClaw-sendable root. WARN lines do not block; FAIL lines are actionable and mean the configuration, OpenClaw CLI capability, or skill sync needs fixing.\n\n## Configuration\n\nRepository config layout:\n\n- `configs/config.example.yaml`: structured config template committed to git\n- `configs/config.yaml`: real local structured config, not committed to git\n- `.example.env`: secret template committed to git\n- `.env`: real local secrets, not committed to git\n\nRules:\n\n- Put only sensitive values in `.env`.\n- Keep structured configuration in YAML.\n- `EMAIL_SMTP_AUTH_CODE` is the SMTP auth code used for email delivery.\n\nInitialization:\n\n```bash\ncp configs/config.example.yaml configs/config.yaml\ncp .example.env .env\n```\n\nThen edit `configs/config.yaml` as needed:\n\n```yaml\nserver:\n  listen: 127.0.0.1:18080 # Service listen address; local-only by default\n  read_timeout: 5s # HTTP request read timeout\n  write_timeout: 30s # HTTP response write timeout\n\nstorage:\n  data_dir: \"\" # Service data directory; empty uses the OS user data directory\n  sqlite_path: \"\" # SQLite database path; empty uses data_dir/imgen.db\n\nscheduler:\n  global_max_concurrency: 10 # Shared serve-mode generation queue cap for submit async and WebSocket realtime\n  default_job_concurrency: 2 # Default per-job concurrency when submit omits --concurrency\n  max_job_concurrency: 10 # Maximum per-job concurrency for submit async jobs\n  max_count_per_job: 10 # Maximum image count for one submit async job\n  maintenance_interval: 5m # Background maintenance interval\n  task_lease_timeout: 30m # Background task lease timeout\n  max_attempts: 3 # Maximum retry attempts per image in submit async jobs\n\nbackend:\n  type: built_in_codex # Use local Codex CLI with the built-in $imagegen skill\n  command: codex # Codex CLI command name or executable path\n  model: \"\" # Empty uses the Codex CLI default model; set this only when pinning a model\n  cwd: \"\" # Codex CLI working directory; empty uses the current process directory\n  timeout: 90s # Timeout for one Codex/imagegen invocation\n  delivery_dir: \"\" # Optional: copy generated images there; OpenClaw/TG can point this at an allowed workspace/media directory\n  delivery_max_files: 200 # Max files to retain in delivery_dir when set; 0 disables automatic cleanup\n  prompt:\n    prefix: \"$imagegen\" # Prefix prepended to every prompt\n    prelude: | # Fixed prompt prelude for default style/output constraints\n      Use the built-in imagegen skill.\n      Output a single image.\n      Default to web or brand asset scenarios.\n\nrealtime:\n  enabled: true # Whether to enable the WebSocket realtime generation endpoint\n  max_sessions: 4 # Maximum active WebSocket generation sessions\n  max_items_per_session: 8 # Maximum items in one WebSocket generate.start frame\n  max_count_per_item: 1 # Maximum image count for one realtime item\n  item_timeout: 300s # Default timeout for one realtime item\n  max_item_timeout: 300s # Maximum client timeout_ms; usually keep this equal to item_timeout\n\nemail:\n  enabled: false # Whether to enable maintenance failure email notification\n  smtp_host: smtp.example.com # SMTP server host\n  smtp_port: 465 # SMTP port; 465 uses implicit TLS\n  from: from@example.com # Sender email and SMTP login identity\n  to: to@example.com # Recipient email\n  timeout: 3s # Timeout for one SMTP connection/send attempt\n  retry_times: 3 # Maximum email send attempts\n  retry_wait_time: 500ms # Wait duration between failed email attempts\n  use_proxy: false # SMTP proxying is not supported yet; keep false\n```\n\nConfiguration fields:\n\n- `server.listen`: service-mode listen address. `127.0.0.1:18080` allows local access only; use `0.0.0.0:18080` only when you intentionally expose it to the network.\n- `server.read_timeout`: HTTP request read timeout.\n- `server.write_timeout`: HTTP response write timeout.\n- `storage.data_dir`: async service data directory. If empty, the user data directory is used. For local development, `./.data` is a good choice.\n- `storage.sqlite_path`: SQLite database path. If empty, `data_dir/imgen.db` is used. For local development, `./.data/imgen.db` is a good choice.\n- `scheduler.global_max_concurrency`: serve-mode bottom generation queue cap shared by async `submit` jobs and WebSocket realtime; it does not affect local sync shorthand generation with `imgen \"prompt\"`.\n- `scheduler.default_job_concurrency`: default async `submit` job concurrency when `--concurrency` is omitted.\n- `scheduler.max_job_concurrency`: maximum async `submit` job concurrency.\n- `scheduler.max_count_per_job`: maximum image count for one async job; larger `--count` input is clamped to this value.\n- `scheduler.maintenance_interval`: service-mode maintenance interval for checks, failure progression, and failure notification.\n- `scheduler.task_lease_timeout`: running-task lease timeout used to detect expired work.\n- `scheduler.max_attempts`: maximum generation attempts per image in async jobs.\n- `realtime.enabled`: whether to enable the WebSocket realtime generation endpoint.\n- `realtime.max_sessions`: maximum active WebSocket generation sessions at the same time.\n- `realtime.max_items_per_session`: maximum items in one WebSocket `generate.start` frame.\n- `realtime.max_count_per_item`: maximum image count per realtime item.\n- `realtime.item_timeout`: default timeout for one realtime item; realtime no longer has its own backend global queue.\n- `realtime.max_item_timeout`: maximum client `timeout_ms`; usually keep it equal to `item_timeout`.\n- `backend.type`: generation backend type. Currently use `built_in_codex`.\n- `backend.command`: Codex CLI command. Defaults to `codex`; the built-in backend currently requires this command to support `exec --json`.\n- `backend.model`: model name passed to Codex CLI. If empty, the configured Codex backend chooses its default model.\n- `backend.cwd`: Codex CLI working directory. If empty, the current process working directory is used. `~/` is expanded.\n- `backend.timeout`: timeout for one Codex/imagegen invocation. Increase it if generation frequently times out.\n- `backend.delivery_dir`: optional delivery directory. When set, generated images are copied there and the copied path is returned. OpenClaw/TG can point this at an allowed workspace/media directory.\n- `backend.delivery_max_files`: maximum retained files in `delivery_dir` when set. Defaults to `200`; set `0` to disable automatic cleanup.\n- `backend.prompt.prefix`: prefix automatically prepended to prompts, usually `$imagegen`.\n- `backend.prompt.prelude`: fixed prompt prelude for default style and output constraints.\n- `email.enabled`: whether to enable maintenance failure email notification.\n- `email.smtp_host`: SMTP server host.\n- `email.smtp_port`: SMTP server port. Port `465` uses implicit TLS; other ports use a timeout-controlled standard SMTP connection.\n- `email.from`: sender email address and SMTP login identity.\n- `email.to`: recipient email address.\n- `email.timeout`: timeout for one SMTP connection/send attempt.\n- `email.retry_times`: maximum email send attempts.\n- `email.retry_wait_time`: wait duration between failed email attempts.\n- `email.use_proxy`: email proxy switch. SMTP proxying is not supported yet; setting this to `true` returns a config error.\n- `.env` `EMAIL_SMTP_AUTH_CODE`: SMTP auth code or password. Required when email is enabled.\n\n## Synchronous text-to-image\n\n```bash\n./imgen \"Generate a 3D-style baby dragon mascot for a web hero section, clean background, single image\"\n./imgen --count 4 --concurrency 2 \"Kuroneko wearing a maid outfit in a cafe\"\n./imgen --count 4 --concurrency 2 --json \"Kuroneko wearing a maid outfit in a cafe\"\n```\n\nText mode prints one image path per line. `--json` prints structured output. Automation should treat `ok: true` plus non-empty `images[].path` values as success, not exit code alone.\n\n## Synchronous image-to-image\n\nUse local image files as references:\n\n```bash\n./imgen --image ./1.png \"Keep the subject composition and pose, convert this image to a high-quality 3D figure render style, cleaner background, single image\"\n./imgen --json --image ./1.png \"Keep the subject composition and pose, convert this image to a high-quality 3D figure render style, cleaner background, single image\"\n```\n\nPass multiple reference images by repeating `--image`:\n\n```bash\n./imgen --image ./1.png --image ./2.png \"Use these images as subject references and generate one consistent high-quality visual\"\n```\n\nNotes:\n\n- Only local file paths are supported in this version. URLs and uploads are not supported.\n- Synchronous `run` and asynchronous `submit` use the same `--image` semantics.\n- The backend invokes Codex CLI as `\u003cbackend.command\u003e exec --json --image ... -- '\u003cprompt\u003e'`.\n- The `--` separator is required for the native Codex CLI command because variadic `--image` would otherwise consume the prompt.\n- Wrappers such as `ccs codex` are not automatically compatible; if `ccs codex exec --json` reports `unknown option '--json'`, the current built-in backend cannot use it directly.\n\nWhen verifying native Codex CLI behavior, first confirm that the executable supports `exec --json`:\n\n```bash\ncodex exec --help\ncodex exec --json -- '$imagegen Generate a cute baby dragon mascot, white background, single image'\ncodex exec --json --image ./1.png -- '$imagegen Keep the subject composition and pose, convert this image to a high-quality 3D figure render style, cleaner background, single image'\n```\n\n## Agent / OpenClaw / Telegram integration\n\nThis project only generates images and returns local file paths. Telegram, OpenClaw, or another agent must read the file pointed to by `images[].path` and upload the file bytes; a local path is not an image URL or a remote file id.\n\nIntegrations should follow this minimal contract:\n\n1. Resolve the config working directory before calling the CLI: prefer `IMGEN_REPO_ROOT`; otherwise walk upward from the current directory until finding `configs/config.yaml` plus `./imgen`, `build.sh`, or `go.mod`; then try explicit user-provided install paths. Do not scan the whole filesystem.\n2. Run `./imgen --json ...` from that directory, or use `./imgen get --json \u003cjob-id\u003e` in service mode.\n3. For OpenClaw/TG, use `IMGEN_DELIVERY_DIR` or `backend.delivery_dir` to copy images into an OpenClaw-sendable workspace/media directory, and use `delivery_max_files` to cap retained delivery files.\n4. Synchronous success requires `ok: true` and non-empty `images[].path` values for the expected images; service jobs expose final files through `images[].path` after completion.\n5. If Telegram reports something like `Media failed`, first check from the Telegram/OpenClaw runtime that `images[].path` exists, is readable, has a valid image format, and is on a shared or copied filesystem.\n\nFor Telegram multi-image requests that need distinct themes, OpenClaw should run independent `./imgen --json --count 1 --concurrency 1` commands concurrently, send each completed `images[].path` immediately with the `message` tool, use `forceDocument` or `asDocument` for original PNG delivery, and return exactly `NO_REPLY` after direct delivery.\n\n### OpenClaw + Telegram quick start\n\n1. Run `./skill-sync --apply` to sync the imgen skill, then restart OpenClaw.\n2. Run `./imgen doctor openclaw` and confirm `message send supports --force-document` is OK and there are no FAIL lines.\n3. Send a Telegram test message, for example: `Generate 3 cat Mac wallpapers with different moods`.\n4. Expect 3 image files/documents. Brief status text and captions are fine, but the literal `NO_REPLY` should not be visible.\n\n`NO_REPLY` is the silent completion signal for OpenClaw: after files have been delivered directly to Telegram, the agent should not add a final text reply.\n\nFor the full OpenClaw reproduction and configuration checklist, see [OpenClaw imgen Integration](./docs/openclaw-imgen-integration.md).\n\n## Service mode\n\nStart the local service in the foreground:\n\n```bash\n./imgen serve\n```\n\nOr use the repository scripts to run it in the background:\n\n```bash\n./start.sh\n./stop.sh\n./restart.sh\n```\n\nThe background script uses `nohup ./imgen serve` and writes logs to `logs/out.log`.\n\nSubmit and query from another terminal:\n\n```bash\n./imgen submit --count 4 --concurrency 2 \"Kuroneko wearing a maid outfit in a cafe\"\n./imgen submit --json --count 4 --concurrency 2 \"Kuroneko wearing a maid outfit in a cafe\"\n./imgen submit --image ./1.png \"Keep the subject composition and pose, convert this image to a high-quality 3D figure render style, cleaner background, single image\"\n./imgen status \u003cjob-id\u003e\n./imgen get \u003cjob-id\u003e\n./imgen get --json \u003cjob-id\u003e\n./imgen list\n./imgen cancel \u003cjob-id\u003e\n```\n\nTo inspect whether a job retried, query the SQLite attempt history:\n\n```bash\nsqlite3 .data/imgen.db \\\n  \"select job_id,image_index,attempt,status,duration_ms,path,last_error from job_image_attempts where job_id='\u003cjob-id\u003e' order by image_index,attempt;\"\n```\n\nTo locate which part of one Codex CLI invocation is slow, inspect phase details:\n\n```bash\nsqlite3 .data/imgen.db \\\n  \"select image_index,attempt,phase,elapsed_ms,detail from job_image_attempt_phases where job_id='\u003cjob-id\u003e' order by image_index,attempt,occurred_at_ms;\"\n```\n\nCommon interpretation:\n\n- Late `process.started`: Codex CLI startup or OS scheduling is slow.\n- Late `stdout.thread_started`: Codex CLI initialization, network, or session creation is slow.\n- Long gap from `stdout.turn_started` to `image.file_detected`: most time is waiting for image generation or file availability.\n- Long gap from `image.file_detected` to `stdout.turn_completed`: the image file is already present, but Codex is still completing its final response or internal turn cleanup.\n- Long gap from `stdout.turn_completed` to `process.exited`: the Codex turn is complete, but the CLI process exit is slow.\n- If `stdout.turn_completed` is missing, a long gap from `image.file_detected` to `process.exited` means the image file is already present, but Codex CLI cleanup/exit is slow.\n- If `image.file_detected` is missing, a long gap from `stdout.turn_started` to `stdout.saved_to` / `process.exited` still points to the model or imagegen tool execution chain.\n- Long gap from `process.exited` to `parser.completed`: local parsing or generated_images directory lookup is slow.\n\n## WebSocket\n\nThe service exposes `/ws?job_id=\u003cjob-id\u003e` for job-scoped event subscriptions. Current event types include:\n\n- `job.created`\n- `job.started`\n- `image.started`\n- `image.completed`\n- `image.failed`\n- `image.cancelled`\n- `job.completed`\n- `job.partial_success`\n- `job.failed`\n- `job.cancelled`\n\nThe WebSocket implementation is intentionally minimal: it supports connection upgrade, `job_id` subscriptions, and event pushes. Historical replay and reconnect recovery are future work.\n\n## Output\n\n- Text mode prints one image path per line.\n- `--json` prints structured output; automation should read `images[].path`.\n- Multi-image sync mode prints one path per line.\n- Service mode supports querying status and image paths by `job_id`.\n- The maintenance ticker is wired into `serve` for minimal checks, failure progression, and final failure notification.\n- Failure email notification is wired into the maintenance path; richer failure classification and immediate notification are future work.\n\n## Development / Testing\n\n```bash\ngo test ./...\nbash ./build.sh\n```\n\nWhen changing CLI flags, config loading, or README content, also verify:\n\n```bash\n./imgen --help\n./imgen --json \"Generate a cute baby dragon mascot, white background, single image\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwalker1211%2Fcodex-imgen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwalker1211%2Fcodex-imgen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwalker1211%2Fcodex-imgen/lists"}