Pixmith

mcp
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Warn
  • process.env — Environment variable access in fixtures/fake-codex.cjs
  • fs module — File system access in fixtures/fake-codex.cjs
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Local MCP server that lets Claude (or any MCP client) generate images by driving the OpenAI Codex CLI — runs on your ChatGPT subscription, no image API key needed.

README.md

Pixmith

Pixmith — a blacksmith's hammer striking a glowing cube of pixels on an anvil in a dark forge, square embers flying

License: MIT
Node.js
MCP
Powered by Codex

Generate images from your MCP client (e.g. Claude) using the OpenAI Codex CLI — on your ChatGPT subscription, no image API key required.

Pixmith is a small local MCP server that lets any MCP
client (such as Claude Desktop or Claude Code) generate and edit images. Under the
hood it drives the OpenAI Codex CLI and its built-in $imagegen skill
(gpt-image-2), then hands the finished PNG back to your client — both as a file path
and inline. Ask Claude for "a watercolour fox at dawn, 1536×1024" and a real image
lands on disk about half a minute later; then say "make it snowing" and Pixmith edits
that same image.

  • One call in the common case. generate_image waits for the image and returns it
    directly; polling is only the fallback for slow jobs.
  • Live feedback. Progress updates carry the real stage reported by Codex and the
    elapsed time against what generations usually take on your machine.
  • Editing. edit_image changes an existing image — a previous result or any local
    file — and both tools accept reference images.
  • Cancellation. cancel_image stops a job and its Codex session immediately.
  • Usage awareness. Every result shows how much of your ChatGPT plan's Codex limit is
    used and when it resets, warns when you are close, and asks before a job would run on
    paid credits.

Why Pixmith? Codex can be signed in with your ChatGPT account, so image
generation runs against your existing ChatGPT plan instead of a separate, metered image
API key. If you already pay for ChatGPT, you get image generation in Claude for no extra
cost — and Pixmith works just as well if your Codex is configured with an OpenAI API key
instead.

ℹ️ Unofficial project. Pixmith is an independent, community tool. It is not
affiliated with, endorsed by, or supported by OpenAI or Anthropic.
"Codex",
"ChatGPT", "OpenAI", "Claude", and "Anthropic" are trademarks of their respective
owners.

⚠️ When using ChatGPT-subscription auth, image generation counts toward your
ChatGPT plan's usage limits.


How it works

MCP client ──MCP(stdio)──▶ Pixmith ──spawn──▶ codex exec "$imagegen …" ──▶ gpt-image-2
                              ▲                                                  │
                              └──────────── PNG path + inline image ◀───────────┘
  1. The client calls generate_image (or edit_image) with a prompt. Pixmith validates
    the request — size, output directory, input images — and queues a job.
  2. Pixmith runs codex exec --json with a tightly-scripted prompt that tells Codex to
    call the built-in image_gen tool exactly once and reply DONE (or
    ERROR: <reason>). Images to edit or reference are attached to that prompt. The
    agent is told not to copy files or run shell commands — Pixmith handles that.
  3. Codex streams JSON events while it works. Pixmith turns them into stages (session
    started, rendering, finishing) and reports them as MCP progress notifications,
    together with the elapsed time and the typical duration of recent jobs.
  4. Pixmith trims the agent's overhead. For plain generations the image prompt is
    handed to the agent in a file, so its tool call stays a few lines long instead of
    retyping the whole prompt token by token. And as soon as the finished PNG is on disk,
    Pixmith stops Codex rather than waiting for the agent's closing turn. Together these
    took a long-prompt 1536×1024 generation from ~46s to ~34s; what remains is almost
    entirely OpenAI's render time.
  5. Codex writes the PNG to $CODEX_HOME/generated_images/<session id>/. Pixmith takes
    the session id from Codex's event stream, copies that session's PNG into the
    requested output directory, and validates it is a real PNG. If no file was written
    (seen on Windows), it decodes the image from the base64 in Codex's output or the
    session's rollout log instead.
  6. The same tool call returns the absolute path plus the image inline. MCP clients cap
    the size of a tool result (Claude Desktop rejects anything over 1 MB) and these PNGs
    are 2–3 MB, so the inline copy is a JPEG preview sized to fit, normally still at full
    resolution up to a 2048px long edge. The full-quality PNG is always the file at the returned path. If the job
    outlasts the wait window (~45s), the call returns a job_id instead and the client
    collects the image with get_image_result.

Because each job is matched to its own Codex session, concurrent jobs can never pick
up each other's image.

No tokens or secrets are ever read, printed, or committed by Pixmith.


Authentication: ChatGPT subscription or API key

Pixmith just shells out to whatever codex you point it at, so it works with either
way of authenticating the Codex CLI:

  • ChatGPT subscription (recommended, no API key): sign in to Codex with your
    ChatGPT account. Image generation is billed against your ChatGPT plan's limits.
  • OpenAI API key: if your Codex CLI is configured to use an OPENAI_API_KEY,
    generation is billed to your OpenAI API account instead. Pixmith does not require
    or read the key itself — it's Codex's own configuration.

Either way, Pixmith does not handle credentials directly.


Prerequisites

Pixmith runs on macOS, Windows, and Linux.

  • The Codex CLI, via one of:
    • the Codex desktop app (bundles the codex binary), or
    • a standalone codex binary on your PATH.
  • Codex signed in — either with your ChatGPT account or configured with an
    OpenAI API key (see above). Verify with codex --version and a quick
    codex exec "hello".
  • Node.js ≥ 18.

Finding the Codex binary

Pixmith auto-detects the Codex binary in the common per-OS install locations and
otherwise falls back to whatever codex is on your PATH. If auto-detection
misses, set CODEX_BIN to the absolute path. To locate it:

OS Find it with Typical location
macOS which codex /Applications/Codex.app/Contents/Resources/codex (desktop app bundle), or ~/.local/bin/codex (standalone installer)
Windows where codex (cmd) %LOCALAPPDATA%\Programs\codex\codex.exe, or %APPDATA%\npm\codex.cmd
Linux which codex /usr/local/bin/codex, ~/.local/bin/codex

If CODEX_BIN points at a file that no longer exists — for example Codex was
reinstalled somewhere else after you configured your MCP client — Pixmith falls back to
auto-detection instead of failing, and adds a Note: to each result so you can clean up
the stale setting.

Windows note: both a native codex.exe and an npm-installed codex.cmd
shim work — Pixmith handles each. If you point CODEX_BIN at a .cmd/.bat,
Pixmith runs it through the shell automatically. Use a full absolute path, and
in JSON configs either use forward slashes (C:/Users/you/...) or escaped
backslashes (C:\\Users\\you\\...).


Install

Every route needs the Codex CLI or the Codex desktop app, signed in with your ChatGPT
account (see prerequisites).

Claude Desktop: one-click bundle

Download pixmith-<version>.mcpb from the
releases page and open it (or drag it
into Claude Desktop's Settings → Extensions). Claude Desktop shows Pixmith's
settings, all optional:

Setting What it does
Codex binary Leave empty to find Codex automatically.
Image folder Where images go. Empty: Pictures/Pixmith in your home folder.
Other folder images may be saved in When set, Claude may save only into this folder or the image folder (PIXMITH_ALLOWED_DIRS).
Images at once How many images may render at the same time (default 1).
Delete Codex's duplicate copies Off by default. When on, Codex's own copy of each image is deleted once Pixmith's is saved (details).

To build the bundle yourself: npm run bundle writes dist/pixmith.mcpb (it installs
only the runtime dependencies into a temporary folder, so dev tools never end up in it).

Claude Code: plugin

In Claude Code, run:

/plugin marketplace add glassd/Pixmith
/plugin install pixmith@pixmith

On Claude Code 2.1.275 or later this works in one step:

/plugin install pixmith --marketplace glassd/Pixmith

The plugin bundles the MCP server and the two skills. Claude Code installs
the npm dependencies itself, so you only need Node.js and a signed-in Codex. Images are
saved to ~/Pictures/Pixmith unless you set PIXMITH_OUTPUT_DIR in your environment.
Pixmith's timing history lives in the plugin's data folder, so it survives updates.

If you registered Pixmith by hand before, remove that entry (claude mcp remove pixmith)
so you don't run two copies.

Any MCP client: npm

Run it with npx; no clone needed. In Claude Desktop's claude_desktop_config.json
(or any client's mcpServers block):

{
  "mcpServers": {
    "pixmith": { "command": "npx", "args": ["-y", "pixmith"] }
  }
}

In Claude Code, prefer the plugin, which adds the skills too; for
the server alone: claude mcp add pixmith --scope user -- npx -y pixmith.

From source

git clone https://github.com/glassd/Pixmith.git
cd Pixmith
npm install

then register it with the path
to src/index.js.

Where files go. Run from a git checkout, Pixmith keeps images in images/ and its
own state in .pixmith/ inside the project, as before. Installed as a bundle or from
npm, the code sits in a folder you never open, so images go to Pictures/Pixmith in
your home folder (or ~/Pixmith without a Pictures folder), and state to
~/Library/Application Support/Pixmith (macOS), %LOCALAPPDATA%\Pixmith (Windows) or
~/.local/state/pixmith (Linux). As a Claude Code plugin, images go to
~/Pictures/Pixmith and state to the plugin's data folder. PIXMITH_OUTPUT_DIR and
PIXMITH_STATE_DIR override all of these.

Run / smoke test

The server speaks MCP over stdio, so normally your MCP client launches it. Running it
directly just verifies it boots:

npm start

Generate a test image directly through the engine (bypasses the MCP protocol):

npm run smoke                       # "a red circle on a white background" @ 1024x1024
node scripts/smoke-test.js "a tabby cat astronaut" 1536x1024
node scripts/smoke-test.js "make the helmet gold" auto /abs/path/to/cat.png   # edit

A successful run prints JSON with the saved path. Images land in ./images/ by
default.

Tests (no Codex needed — a fake Codex in fixtures/ stands in for it):

npm test

CI runs the same suite on Linux for Node 18, 20, 22 and 24, and on macOS and Windows for Node 24.

Lint and formatting (ESLint for correctness, Prettier for layout; both need Node 20.19+):

npm run lint          # ESLint
npm run format        # rewrite files with Prettier
npm run format:check  # what CI checks

The tools

A generation is a Codex agent session, so it takes roughly 30–40s (edits about twice
that) — close to the per-request timeout some MCP clients enforce. Pixmith therefore
never blocks a single call for longer than the wait window (PIXMITH_POLL_WAIT_MS,
default 45s). A typical generation fits inside it, so the usual flow is one tool
call that returns the image
. If the window closes while Codex has already finished and
the image is only being collected, the call waits up to 8s more (never beyond 58s in
total) rather than costing another round trip. Slower jobs fall back to a job_id plus
get_image_result. The assistant drives all of this automatically.

generate_image — make an image

Param Type Required Description
prompt string ✅ Text description of the image.
size string ❌ auto, a shortcut 1K/2K/4K, or explicit WIDTHxHEIGHT (e.g. 1024x1024, 1536x1024, 3840x2160). See size limits. Default 1024x1024.
reference_images string[] ❌ Up to 4 absolute paths of images (PNG, JPEG, WebP, GIF) to use as style, composition or subject references.
background string ❌ auto (default: transparent only if the prompt asks for it), transparent (a PNG with an alpha channel, the subject alone, for logos, icons and stickers) or opaque. See backgrounds.
variants integer ❌ 1–4, default 1. How many alternative images to make. Each is a full generation against the plan's usage. See variants.
filename string ❌ File name for the PNG, without a folder (e.g. hero-banner). Cleaned to letters, digits, ., _ and -; never overwrites, adding -2, -3… instead. Default: made from the prompt.
output_dir string ❌ Absolute directory to save into. Defaults to Pixmith's images/ folder.
wait boolean ❌ Default true: wait up to the wait window and return the image directly. false returns the job_id at once — handy for starting several jobs back to back.
use_credits boolean ❌ Only matters once the plan limit is used up: confirms that you agreed to continue on paid credits. See plan usage and credits.

Invalid sizes, relative output_dir paths and unreadable input images are rejected
here, before any Codex session starts. If more than PIXMITH_MAX_CONCURRENT jobs are in
flight the new one is reported as status: queued with its position.

edit_image — change an existing image

Param Type Required Description
image string ✅ Absolute path of the image to edit — a previous Pixmith result or any local PNG, JPEG, WebP or GIF (max 20 MB).
prompt string ✅ What to change. Say what must stay the same, e.g. "make the sky stormy; keep everything else unchanged".
reference_images string[] ❌ Extra images to borrow style or content from (up to 4 images in total).
size string ❌ As above. Defaults to auto, which keeps the source's aspect ratio.
background, variants, filename, output_dir, wait, use_credits ❌ As for generate_image.

The source file is never modified; the edit is saved as a new PNG. Every finished result
ends with the exact edit_image call that would refine it, so iterating is a one-liner
for the assistant.

pixmith_status — check the setup

No parameters. Checks everything that decides whether an image can be made, without
making one (so it uses no plan quota), and says what to do about each problem:

Pixmith 0.6.1: ready to make images.

Codex: version 0.46.0 at /opt/homebrew/bin/codex
Signed in: yes, with a ChatGPT account
Plan usage: 12% of the 5-hour limit (resets at 18:40), 3% of the weekly limit (resets Mon at 09:00).
Output folder: /Users/you/Pixmith/images (writable)
Jobs: 0 running, 0 queued
Settings: up to 1 job at a time, 45s wait window, 300s timeout, sandbox workspace-write, credits policy "ask"
Running on Node 22.12.0 (darwin).

It runs codex --version and codex login status (neither starts a session) and reads
the latest plan-usage figures. Problems it reports: Codex not found, not signed in, the
plan's limit reached, an unwritable output folder. Warnings cover settings that were
ignored, a stale CODEX_BIN, and a Codex signed in with an API key, which bills
images to that API account instead of the ChatGPT plan. Pixmith never reads Codex's
credentials: with a Codex too old to have login status, it only checks whether the
credentials file exists.

Backgrounds

background: "transparent" asks for a PNG with an alpha channel: the subject alone, with
no backdrop, floor or shadow. The image tool only takes a prompt, so this is an
instruction to the model rather than a switch, and it does not always follow it. Pixmith
therefore checks the PNG it gets back and says so: Background: transparent (the PNG has an alpha channel)., or a note that the background came out opaque, so you can retry
(has_alpha in structured results). An inline JPEG preview cannot
show transparency, so transparent areas look white there; the PNG on disk keeps them.
background: "opaque" rules transparency out even when the prompt mentions it.

Variants

variants: 3 makes three alternative images from one prompt. Each is its own Codex
session and job, so each counts toward the plan's usage like a separate request, and
they run one after another unless PIXMITH_MAX_CONCURRENT is raised. The call waits for
them within the usual window and returns all that are ready, each with its path and
job_id and the inline images side by side (sharing the client's size limit, so the
previews are smaller). Any still running are collected with get_image_result and their
own job_id. With a filename, variants are numbered: logo-1.png, logo-2.png, …

get_image_result — collect a slower job

Param Type Required Description
job_id string ❌ The job to fetch. Optional only when a single job could be meant (see below); pass it always.

Waits up to the wait window, then returns. While the job is waiting for a slot or still
rendering it returns status: queued or status: running with the current stage,
elapsed time and an estimate of what is left; the assistant simply calls it again until
status: done. Results can be fetched more than once, so an image is never lost to a
client-side timeout. A finished image's job_id keeps working afterwards, even after
Pixmith restarts (it is looked up in the image history).

Without a job_id. An MCP client such as Claude Desktop runs one Pixmith server for
all its conversations, and Pixmith cannot tell them apart, so "the latest job" may be
another conversation's. Without a job_id, get_image_result therefore picks a job only
when exactly one could be meant: the only job whose result has not been returned yet
(queued, running, or finished after its call timed out), or failing that the only job that
finished in the last 10 minutes. The result then says which prompt it picked. When several
jobs qualify it picks none and fails with [ambiguous_job], listing each candidate's
job_id, status, age and first words of its prompt (also as candidates in the
structured output).

cancel_image — stop a job

Param Type Required Description
job_id string ❌ The job to cancel. Optional only when a single job is queued or running.

A queued job is dropped; a running job's Codex session is killed at once, so it stops
using your ChatGPT quota. Without a job_id it cancels the only queued or running job;
with several, it cancels nothing and fails with [ambiguous_job], listing them. Pixmith also stops every running session when the MCP client
disconnects.

list_images — find earlier images

Param Type Required Description
limit integer ❌ How many to return, 1–50. Default 10.
query string ❌ Only images whose prompt contains this text (case-insensitive).
mode string ❌ generate or edit: only generated, or only edited, images.

Lists finished images newest first, each with its time, mode, size, prompt, path, the
image an edit was made from, and its job_id, so you can say "edit the fox picture from
earlier" and the assistant can find it. It covers every output folder, and leaves out
images that have been deleted since.

The list comes from Pixmith's image history, history.jsonl in its state folder
(PIXMITH_STATE_DIR, default .pixmith/), which gets one line per finished image and
keeps the newest 1,000 (it is trimmed back to 1,000 once it passes 1,500). It holds your prompts; delete the file to clear the history.
Servers sharing a state folder (e.g. Claude Desktop and Claude Code) share the history.

Structured results

Besides the readable text (and the inline image), every result carries
structuredContent that matches the tool's declared outputSchema, so a client or
script can read the outcome without parsing text. generate_image, edit_image and
get_image_result share one shape:

{
  "status": "done",
  "job_id": "3f9c…",
  "mode": "generate",
  "path": "/abs/path/images/a-red-fox-….png",
  "size": "1024x1024", "width": 1024, "height": 1024,
  "requested_size": "1024x1024",
  "bytes": 2481152,
  "elapsed_seconds": 34,
  "inline_image": { "mime_type": "image/jpeg", "width": 1024, "height": 1024, "preview": true },
  "usage": {
    "plan": "plus",
    "windows": [{ "label": "5-hour", "used_percent": 12, "resets_at": "2026-10-05T23:10:00.000Z" }],
    "near_limit": false,
    "credits_available": false
  }
}
  • status is queued, running, done, cancelled or error. A queued or running
    job adds stage, queue_position, elapsed_seconds and expected_seconds; an edit
    adds source_image.
  • A failure has status: "error" and an error object with a machine-readable kind
    (bad_request, usage_limit, credits_confirmation_needed, not_signed_in,
    timeout, …), the message, and usually a next_step.
  • A finished image also reports the background asked for and has_alpha, whether the
    PNG has an alpha channel.
  • A call with variants above 1 returns job_ids and a variants array holding each
    variant's result in this same shape; the top-level status summarises them (done once
    every variant has finished and at least one succeeded).
  • cancel_image returns the job's status after the call, cancel_requested, and the
    previous_status it had.

Set PIXMITH_STRUCTURED_OUTPUT=false to leave it out, for a client that mishandles
structured tool results.

Metadata sidecar

Every image gets a small JSON file beside it with the same name (a-red-fox-….png →
a-red-fox-….json), recording how it was made:

{
  "pixmith_version": "0.6.1",
  "created_at": "2026-10-05T21:40:12.345Z",
  "mode": "edit",
  "prompt": "make the sky a stormy purple; keep everything else unchanged",
  "image": "make-the-sky-a-stormy-purple-keep-everyt-….png",
  "sha256": "9b1f…",
  "size": "1536x1024", "width": 1536, "height": 1024,
  "requested_size": "auto",
  "source_image": "/abs/path/images/a-red-fox-….png",
  "reference_images": [],
  "codex_session_id": "0199…",
  "duration_ms": 61234
}

An edit names the image it was made from, so a chain of edits can be followed back to
the original prompt; sha256 identifies the image even after it is moved or renamed.
The metadata sits beside the PNG rather than inside it, so the image is exactly what the
model produced and sharing it never shares the prompt. The result's Metadata: line
(metadata_path in structured results) gives its path. Set
PIXMITH_METADATA=false to stop writing it.

Codex's duplicate copies

Codex keeps its own copy of every image under ~/.codex/generated_images/ (2–3 MB
each), next to the one Pixmith saves for you, so by default every image takes twice the
space. pixmith_status shows how much that is. Two ways to reclaim it:

  • New images: set PIXMITH_CODEX_COPIES=remove, and Pixmith deletes Codex's copy
    (and its emptied session folder) as soon as its own copy is saved. The default is
    keep, because those files belong to Codex and the Codex app may show them.
  • Existing images: run the command pixmith_status prints, e.g.
    npx pixmith prune-codex-copies --state-dir <folder> (from a source checkout:
    node src/index.js prune-codex-copies); add --dry-run to see what it would delete
    first. --state-dir points it at the server's own image history, which matters for
    the plugin and the Desktop bundle, and --codex-home covers a non-default CODEX_HOME. It works from the image history and deletes
    a Codex copy only when Pixmith's copy still exists with exactly the same bytes, and only
    inside generated_images (a symlink cannot lead it anywhere else).

Codex's session logs (~/.codex/sessions/) also carry each image, base64-encoded.
Pixmith leaves those alone: Codex uses them for its history, and Pixmith reads the plan's
usage from them.

Plan usage and credits

Codex records your ChatGPT plan's limits in its session logs. Pixmith reads the latest
snapshot (it never reads auth tokens) and ends every finished result with a line like:

Plan usage: 16% of the 5-hour limit (resets at 21:37), 3% of the weekly limit (resets Wed at 17:36).

Past PIXMITH_USAGE_WARN_PERCENT (default 80%) a warning is added, saying what happens
next: either jobs will continue on paid credits and how many you have, or they will stop
until the reset unless you add credits (ChatGPT → Settings → Usage, or Usage & Billing in
the Codex app).

Once a limit is fully used, Codex would draw on purchased credits automatically. Pixmith
does not let that happen silently. (If the account has credits, the question comes
slightly early, at 98%: a generation uses 1–2% of the 5-hour window, so a job started
above that could cross the limit mid-run.) generate_image and edit_image refuse to start
with [credits_confirmation_needed] and tell the assistant to ask you. If you agree,
the assistant repeats the call with use_credits: true. Set PIXMITH_USE_CREDITS to
always to skip the question or never to refuse outright. Pixmith never buys credits.

The snapshot is only as fresh as your last Codex run, so usage from other Codex sessions
since then is not reflected, and credits bought a minute ago may not show yet — which is
why the confirmation can always be overridden with use_credits: true.

Progress feedback

While a call waits, Pixmith sends MCP progress notifications every 3 seconds, for
clients that display them:

Codex session started — 3s of ~32s
Rendering the image — 18s of ~32s
Rendering the image — 41s, longer than the usual ~32s

The stage comes from Codex's own event stream. The "usual" figure is the median of your
last ten jobs (kept separately for generations and edits in .pixmith/stats.json), so
the estimate adapts to your machine, plan and image sizes.

Size limits

gpt-image-2 accepts auto or any WIDTHxHEIGHT where:

  • each edge is a multiple of 16 (Pixmith rounds for you and notes it in the result),
  • the longest edge is at most 3840 px,
  • the long-to-short aspect ratio is at most 3:1, and
  • the total pixel count is between 655,360 and 8,294,400.

Popular sizes: 1024x1024, 1536x1024, 1024x1536, 2048x2048, 3840x2160,
2160x3840. Requests outside these limits fail fast with a [bad_request] error
instead of after a full generation.

The model does not always return exactly the requested size (a 1024x1024 request
may come back as 1254x1254, and auto has no fixed size). Pixmith reads the real
width and height from the saved PNG and reports those, noting the requested size
when it differs.


Skills

Pixmith passes your assistant's prompt to gpt-image-2 word for word, so the result is
only as good as the prompt. Two skills teach Claude to make the most of that:

  • image-prompts — how to write a strong gpt-image-2 prompt (use, subject, style,
    composition, light, exact text), choose a size, use reference images, and refine a
    result with targeted edits. Claude loads it whenever it is about to make or edit an
    image.
  • project-images — images for a codebase at exact specs: favicons, app icons, Open
    Graph cards, README banners, hero images. It generates at a size the model accepts,
    then uses a bundled script to crop and resize to exact pixels, build multi-size
    favicon.ico files and transparent cutouts, and wires the files into the HTML,
    framework metadata, web manifest or README.

The plugin install includes both. For a manual install in Claude Code, link them into
your personal skills folder so the bundled script can still find Pixmith's dependencies:

mkdir -p ~/.claude/skills
ln -s /path/to/Pixmith/skills/image-prompts ~/.claude/skills/image-prompts
ln -s /path/to/Pixmith/skills/project-images ~/.claude/skills/project-images

Claude Desktop and claude.ai accept uploaded skills too. Each
release includes
pixmith-image-prompts-skill.zip: download it and add it under Skills in Claude's
settings. project-images relies on running its script locally, so it is meant for
Claude Code; its zip is attached as well for anyone who wants it elsewhere.


Environment variables

Variable Default Purpose
CODEX_BIN auto-detected, else codex on PATH Path to the Codex binary. Set this if auto-detection misses (e.g. CODEX_BIN=C:/Users/you/AppData/Local/Programs/codex/codex.exe).
PIXMITH_SANDBOX workspace-write Sandbox policy passed to codex exec when the OS sandbox is used: read-only, workspace-write or danger-full-access. Anything else is ignored with a startup warning.
PIXMITH_BYPASS_SANDBOX true on Windows, else false Run Codex without its OS sandbox. Codex sandboxing is macOS/Linux only (Seatbelt/Landlock); on Windows it blocks the file-save, so Pixmith bypasses it there. Set true/false to override.
PIXMITH_POLL_WAIT_MS 45000 (45s) The wait window: the longest any single tool call waits for a job (2s–55s). Lower it if your MCP client's request timeout is under ~60s.
PIXMITH_EARLY_EXIT true Stop Codex as soon as the finished PNG is on disk instead of waiting for the agent's closing turn (saves ~4–7s and the tokens of re-uploading the image).
PIXMITH_FAST_PROMPT true (false on Windows) Hand the image prompt to the agent in a temp file so it does not retype it into its tool call (saves ~1s per 150 characters of prompt). Generations only; edits keep the agent's own rewrite. Falls back to the normal path if Codex's script tools are unavailable.
PIXMITH_CODEX_MODEL (Codex config) Model for the agent that wraps the image call, e.g. a faster one. Does not change the image model. In testing this made little difference — the wrapper's cost is output speed, which the fast path removes. A value with characters outside letters, digits, ., :, -, _ is ignored, with a warning in the server's startup log.
PIXMITH_CODEX_EFFORT (Codex config) Reasoning effort for that agent (low, medium, …).
PIXMITH_SHOW_USAGE true Add the plan usage line (and near-limit warning) to results.
PIXMITH_USAGE_WARN_PERCENT 80 Warn once any plan window is this full.
PIXMITH_USE_CREDITS ask When the plan limit is used up: ask (require use_credits: true), always (run on credits without asking), or never (refuse).
PIXMITH_STATE_DIR <project>/.pixmith (installed: per-user app folder; plugin: its data folder; see where files go) Where Pixmith keeps its own state: recent job durations (used for time estimates) and the image history behind list_images.
PIXMITH_OUTPUT_DIR <project>/images (installed: ~/Pictures/Pixmith) Default output directory for generated PNGs. A leading ~ means your home folder. The Claude Code plugin sets its default through PIXMITH_DEFAULT_OUTPUT_DIR, so your own PIXMITH_OUTPUT_DIR still takes priority.
PIXMITH_ALLOWED_DIRS (unset: any folder) Folders output_dir may point into, separated like PATH (: on macOS/Linux, ; on Windows), e.g. /Users/you/Pictures:/Users/you/projects or ~/Pictures:~/projects. The default output folder is always allowed. See security notes.
CODEX_HOME ~/.codex Codex home (used to locate the backup generated_images/ copy).
PIXMITH_TIMEOUT_MS 300000 (5 min) Hard timeout per generation.
PIXMITH_MAX_CONCURRENT 1 How many Codex generations may run at once. Extra jobs queue.
PIXMITH_RETURN_IMAGE true Set false to return only the path, never inline bytes.
PIXMITH_STRUCTURED_OUTPUT true Declare an outputSchema on each tool and return structuredContent next to the text. See structured results.
PIXMITH_CODEX_COPIES keep remove deletes Codex's own copy of each image once Pixmith's is saved. See Codex's duplicate copies.
PIXMITH_METADATA true Write a <image>.json sidecar beside each PNG with its prompt, sizes, sources and SHA-256. See metadata sidecar.
PIXMITH_MAX_INLINE_BYTES 696320 (680 KB) Byte budget for the inline image. A PNG over it is sent as a JPEG preview that fits (quality 85, long edge at most 2048px, downscaled further only if needed). The default keeps the whole result under Claude Desktop's 1 MB tool-result cap, since base64 adds a third. Raise it only for clients without that cap.

See .env.example for a copy-paste starting point.


Register Pixmith as a connector in your MCP client

For a source install. (The bundle and the plugin register themselves,
and the npm route only needs the npx entry above.) Pixmith does not register
itself from source: replace
/path/to/Pixmith below with the absolute path where you cloned this repo.

Claude Desktop

Edit the Claude Desktop config and add a pixmith entry under mcpServers (merge
with anything already there):

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

macOS / Linux:

{
  "mcpServers": {
    "pixmith": {
      "command": "node",
      "args": ["/path/to/Pixmith/src/index.js"]
    }
  }
}

Windows (note forward slashes, or escaped \\, in JSON):

{
  "mcpServers": {
    "pixmith": {
      "command": "node",
      "args": ["C:/path/to/Pixmith/src/index.js"]
    }
  }
}

CODEX_BIN is auto-detected, so it's usually omitted. Add it under "env" only
if you need to override the detected path, e.g.
"env": { "CODEX_BIN": "C:/Users/you/AppData/Local/Programs/codex/codex.exe" }.

Then quit and reopen the app. Pixmith appears as a connector exposing the
generate_image, edit_image, get_image_result, cancel_image, list_images and
pixmith_status tools.

Claude Code (CLI)

The plugin is the easiest route. To register a
source checkout by hand instead:

claude mcp add pixmith --scope user -- node /path/to/Pixmith/src/index.js

Or add the same mcpServers block above to a project-level .mcp.json.

Try it

Use Pixmith to generate a 1536x1024 image of a lighthouse at sunset.

Now make it a stormy night, keep the lighthouse exactly as it is.


Troubleshooting

Start by asking the assistant to run pixmith_status: it checks Codex, the sign-in,
plan usage and the output folder, and says what to do about each problem it finds.

Symptom Cause / fix
[binary_missing] Codex CLI not found in CODEX_BIN or any of the usual locations — install it, or set CODEX_BIN to the correct path. Apps launched from the Dock don't see your shell's PATH, so use an absolute path.
[not_signed_in] Sign in to Codex (ChatGPT account) or configure an API key, then retry.
[dir_not_allowed] output_dir is outside PIXMITH_ALLOWED_DIRS. Save into an allowed folder (or leave output_dir out), or add the folder to PIXMITH_ALLOWED_DIRS in your MCP client's config.
[timeout] Large image or slow service — raise PIXMITH_TIMEOUT_MS.
[usage_limit] Your ChatGPT plan's image/Codex limit was reached. Retry after it resets, or add credits.
[credits_confirmation_needed] The plan limit is used up and the job would run on paid credits. Tell the assistant whether to continue; see plan usage and credits.
[generation_failed] / [no_output] Codex ran but produced nothing; see the Detail: stderr tail in the error.
Windows: image isn't saved / sandbox error Codex's OS sandbox is macOS/Linux only and blocks file writes on Windows. Pixmith bypasses it on Windows automatically (PIXMITH_BYPASS_SANDBOX=true). If you overrode that, unset it.
Client times out during generation No call waits longer than the wait window (45s by default). If your client's request timeout is shorter than ~60s, lower PIXMITH_POLL_WAIT_MS to match. The job keeps running either way — call get_image_result with its job_id (or with no arguments, if it is the only job in progress) to collect it.
"Tool result is too large. Maximum size is 1MB." Your client caps tool results and PIXMITH_MAX_INLINE_BYTES is set too high for it (versions before 0.5.1 defaulted to 6 MB). Remove the override, or set it to 696320 or lower.
[unknown_job] The job_id expired (>15 min) or nothing was started — call generate_image first. Without a job_id: no job is in progress or finished in the last 10 minutes.
[ambiguous_job] get_image_result or cancel_image was called without a job_id while several jobs could be meant (perhaps from other conversations). Call again with one of the listed job_ids.
[bad_request] The size breaks a gpt-image-2 limit (see size limits), output_dir is not absolute, or an input image is missing, too large, or not a PNG/JPEG/WebP/GIF. Fix the argument and retry.
An edit changed more than asked Say explicitly what must stay the same ("change only X; keep Y unchanged"), and pass a fixed size if the framing moved.
Jobs sit at status: queued More jobs were started than PIXMITH_MAX_CONCURRENT allows. They run in order; raise the limit if your plan can take it.

A note on timing. A generation is an agent session, not a raw API call, so it
takes ~30–40s (edits longer). Pixmith never blocks a call past the wait window: a
typical image comes back from the first call, and anything slower returns a job_id
that get_image_result collects with short, bounded waits.


Security notes

  • Pixmith never reads, prints, or commits Codex auth tokens (e.g. ~/.codex/auth.json).
  • node_modules/, generated images, and any .env/auth.json/key files are
    git-ignored.
  • On macOS and Linux, Codex runs with the workspace-write sandbox scoped to the
    output directory. On Windows there is no OS sandbox (Codex's Seatbelt/Landlock
    sandboxing is Unix-only), so Pixmith runs Codex unsandboxed there by default. The
    agent is instructed not to run shell commands, but that is a prompt, not a policy.
    Treat image prompts there as able to reach a shell, and only pass prompts you trust.
  • On Windows, an npm-installed codex.cmd has to be run through cmd.exe. Pixmith
    refuses to pass it any path containing % ! ^ & | < > (characters cmd.exe would
    interpret), so a crafted output_dir or image path cannot run commands. Point
    CODEX_BIN at a codex.exe to avoid the shell, and the restriction, entirely.
  • Input images for edit_image / reference_images must be absolute paths to real image
    files (checked by magic bytes, max 20 MB). They are attached to the Codex prompt, so
    they are uploaded to OpenAI as part of the request; the files themselves are never
    modified.
  • output_dir must be an absolute path; relative paths are rejected so the MCP
    client's working directory never decides where files land.
  • output_dir is chosen by the model, which can be steered by text it reads (a web
    page, a document). By default any absolute folder is accepted, and on macOS and Linux
    it is also made writable for Codex's sandbox. Set PIXMITH_ALLOWED_DIRS to limit
    it to folders you choose: anything outside them is refused before a job starts, with
    symlinks resolved so a link inside an allowed folder cannot lead out of it.
    pixmith_status shows the folders in effect.

Releasing

  1. Set the same version in package.json, manifest.json and
    .claude-plugin/plugin.json (the tests fail if they differ). Plugin users only receive
    an update when this version changes.
  2. Merge to main, then push a matching tag: git tag v0.6.0 && git push origin v0.6.0.
  3. The release workflow checks the versions, runs the tests, creates a GitHub Release
    with the Claude Desktop bundle (pixmith-<version>.mcpb) and the two skills as zip
    files, and publishes to npm.

npm publishing uses trusted publishing: on
npmjs.com, the pixmith package's Trusted Publisher settings name GitHub Actions,
glassd / Pixmith and the workflow file release.yml, with npm publish allowed. No
npm token is stored in the repository.


License

MIT.

Reviews (0)

No results found