dsh-openai-codex-image
A DeepSeek Harness (DSH) plugin that signs in with a ChatGPT account (Codex OAuth) and generates images through the ChatGPT subscription quota instead of a paid API key.
Why
OpenAI's gpt-image-2 is documented for the paid API-key path (api.openai.com). If you already pay for ChatGPT, an agent that calls the image API pays for the same model twice. This plugin follows the same route the Codex CLI uses:
POST https://chatgpt.com/backend-api/codex/responses
tools: [{ type: "image_generation", model: "gpt-image-2", size }]
tool_choice: { type: "image_generation" }
…authenticated with the ChatGPT OAuth access token + chatgpt_account_id. Image calls ride the ChatGPT subscription instead of API credits.
This is an unofficial integration of a Codex CLI endpoint. It is not affiliated with OpenAI, and OpenAI may change the endpoint at any time. Make sure using it complies with the terms that apply to your account.
Demo
Both images were generated with generate_image through a ChatGPT subscription account:
1024x1024 request (actual 1312x1199) |
1536x1024 + quality=low (actual 1672x941) |
|---|---|
![]() |
![]() |
Features
generate_imagetool: prompt → PNG file in your workspace, displayed inline in chat when the active model accepts image input.openai_accounttool: status / device-code login / poll / logout.- Settings → ChatGPT Image page: authorization status (source, account, plan, token expiry), the device-code login flow, sign-out, and the current image defaults — the same-origin routes never return tokens.
- Auth resolution: plugin-owned OAuth record in DSH credentials first, then the local Codex CLI login (
~/.codex/auth.json, read-only). - Automatic token refresh for the plugin-owned record (refreshed tokens are written back to the same DSH credential record).
- No hard dependency on
@deepseek-ai/*packages: the plugin only uses Node built-ins and the services on the DSH context, so it works as a locally installed bundle. - Original SVG icon, localized metadata (en / zh).
Requirements
- DSH Desktop (or a DSH profile with the
credentials,attachments,workingDirectoryandllmservices). - Node.js
^22.19.0 || >=24.0.0. - A ChatGPT account that can use Codex, logged in either through:
- the Codex CLI (
codex login), or - this plugin's device-code flow.
- the Codex CLI (
Install
git clone https://github.com/kkczx5428/dsh-openai-codex-image.git
In a DSH session, ask the agent to run:
plugin_manager(action="install_bundle", target="<absolute path to the cloned directory>")
install_bundle links the directory into the active profile and appends the bundle to the profile. Restart DSH after changing plugin source; installing a new bundle applies immediately.
To remove it:
plugin_manager(action="remove_bundle", target="openai-codex-image")
Usage
generate_image(prompt="A red panda with round glasses using a glowing laptop, cozy study, 3/4 view")
generate_image(prompt="...", size="1536x1024", quality="low", output_dir="assets")
| Parameter | Required | Description |
|---|---|---|
prompt |
yes | Image description; Chinese and English both work |
size |
no | 1024x1024 (default), 1536x1024, 1024x1536, 2048x2048, 2048x1152, 3840x2160, 2160x3840 |
quality |
no | auto / low / medium / high |
model |
no | Image model, default gpt-image-2 |
host_model |
no | Conversation model that hosts the image_generation tool; default from config |
output_dir |
no | Relative to the session workspace, or an absolute path; default generated_images |
file_name |
no | Optional file name (.png is appended, path parts are stripped) |
Returns path, actual width/height, bytes, model, requested size, optional revised_prompt, and an image attachment block when the active model accepts image input.
The backend snaps requested sizes to the aspect ratios it supports; the returned dimensions are the real ones.
Account authorization
| Action | Purpose |
|---|---|
status |
Show auth source, account, plan, token expiry, image defaults |
login_start |
Start OpenAI device-code login; returns https://auth.openai.com/codex/device plus an 8-character code |
login_poll |
Call after finishing browser login to exchange and store the token |
logout |
Delete the plugin-owned credential (the Codex CLI login is left untouched) |
Device-code flow:
openai_account(action="login_start")→ open the URL, enter the code;- complete the ChatGPT login in the browser;
openai_account(action="login_poll")→authorized;generate_imagenow uses that authorization.
Settings page
DSH → Settings → ChatGPT Image shows the current authorization source, account, plan and token expiry, starts the device-code login, confirms it, and signs the plugin-owned credential out. It reads the plugin's own same-origin routes under /api/openai-codex-image/*; the page receives no tokens (the account id is masked).
The page is the browser half of the bundle (client.js). Client bundles load when the host starts, so restart DSH Desktop after installing or upgrading this plugin to see a new or changed settings page.
Authentication sources
- Plugin credential — DSH credential record
openai-image/chatgpt(kind: "grant", payload{ type: "oauth", access, refresh, expires, accountId, ... }). Refreshed automatically 60 seconds before expiry; refreshed tokens replace the same record. - Codex CLI —
~/.codex/auth.json(auth_mode: "chatgpt"). Read-only: the plugin never writes to it, so token rotation in the Codex CLI stays consistent. If it is expired, the plugin asks you to runcodex loginor use the device-code flow.
Configuration
All keys are optional and live in the bundle's cordis.patch.yml row config:
| Key | Default | Description |
|---|---|---|
authFile |
~/.codex/auth.json |
Codex CLI login file |
hostModel |
gpt-6.1-sol |
Conversation model hosting image_generation |
imageModel |
gpt-image-2 |
Image model |
defaultSize |
1024x1024 |
Default size |
outputDir |
generated_images |
Default output directory |
timeoutMs |
240000 |
Per-request timeout, 30s–600s accepted |
Troubleshooting
| Symptom | Meaning / fix |
|---|---|
HTTP 400 ... model is not supported when using Codex with a ChatGPT account |
The host model is unavailable for your account. Pass another host_model (values can be found in Codex's models_cache.json, e.g. gpt-6.1-sol, gpt-6-sol, gpt-5.6-sol). |
HTTP 401/403 |
Authorization invalid or expired; run openai_account(action="login_start"). |
HTTP 429 |
Rate or quota limit; wait for the subscription quota to reset. |
| Timeout | Raise timeoutMs; typical generations take 20–60 s, larger sizes longer. |
| Image not shown inline | The active model does not accept image input; the PNG is still saved at path. |
| Settings page missing after install/upgrade | Client bundles load at host start; restart DSH Desktop. |
Development
node --check index.js # syntax
node scripts/smoke.mjs # registration/schema smoke test, no network
dsh.client + ./client export are what make the Settings page load. exports must include "./package.json": "./package.json": DSH's client-module scan locates a bundle's manifest through require.resolve("<package>/package.json"), and without that subpath export the scan silently skips the package — the host half and tools work, but the settings page never appears.
Layout:
index.js # all plugin logic (Host half, Node built-ins only)
client.js # Settings page (browser half, hand-written ModuleLoader bundle)
cordis.patch.yml # inserts the openai-codex-image row
package.json # dsh.bundle.patch -> cordis.patch.yml; dsh.client -> client.js
locale/en.json # plugin manager title/description
locale/zh.json
icon.svg # original SVG icon
scripts/smoke.mjs # offline smoke test (tools, manifest, Web API routes)
generated/ # local test output (git-ignored)
Verified end-to-end on Windows (2026-10-26): real image generation through a ChatGPT subscription account, inline image results, sized and quality-controlled output, the error paths above, and the full device-code login (login_start → browser login → login_poll → credential stored in DSH → generation using that stored credential). CI covers the offline smoke test only; network and account flows need a real account.
Security
- Tokens live only in the DSH credential store and in the Codex CLI's own
~/.codex/auth.json; the plugin never logs or copies them. logoutremoves only the plugin-owned record; runcodex logoutseparately to sign the Codex CLI out.- Prompts are sent to OpenAI — that is inherent to image generation.
- See SECURITY.md for reporting vulnerabilities.


No comments yet. Be the first to write one.