AI-assisted automatic development of RAW photographs.
Point it at a RAW (or an exported PNG/TIFF); an AI advisor decides the develop adjustments and a deterministic Rust engine applies them — or writes an XMP sidecar so the edit opens as adjustable sliders in Lightroom.
The judgement-heavy part of developing a photo is deciding what to change (this sky is blown, those shadows are crushed, the white balance is too cool). The mechanical part is applying it. Autoshop splits exactly there:
RAW ─► decode + features ─► [GPT vision advisor] ─► EditRecipe ─► [Claude verify] ─► Rust render engine
.ARW preview+EXIF+hist looks at photo JSON QA / accept │
▼
XMP sidecar + 16-bit master
The AI never touches a pixel in the main path. The vision model only emits an
EditRecipe — a small, bounded, Lightroom/ACR-style JSON of
slider values — and a deterministic engine renders from the original RAW. That
keeps results reproducible, non-destructive, auditable, and free of hallucinated
detail. (Three opt-in, clearly-labelled exceptions touch pixels: AI denoise,
generative retouch, and pixel heal — see below.)
- One-shot develop —
autodecodes a RAW, asks GPT for anEditRecipe, has Claude acceptance-verify it, then renders a 16-bit TIFF master. - XMP sidecar — the same recipe serialises to an ACR/Lightroom
.xmp(global sliders + local linear/radial masks), so the AI's edit opens as fully-adjustable sliders in your catalog. - AI Denoise (SCUNet, GPU) — ACR/LR-style denoise for high-ISO / astro frames. Off by default, triggered by a flag, a CLI command, or a UI button.
- PNG/TIFF source mode — feed an already-processed image (e.g. denoised in Lightroom/Photoshop) and Autoshop grades it directly. Auto-detected by file type; no RAW required. Embedded ICC profiles (LR "Edit in…" exports ProPhoto 16-bit by default) are normalised into the sRGB working space — 16-bit depth preserved — instead of being read as if they were sRGB.
- Desktop app (native GUI) —
autoshop-gui: a library grid that marks which photos already have a saved develop, the full develop panel (tone, presence, curves, 8-band HSL, colour grading), local masks (linear / radial / brush / AI-selected — rotatable radials, add/subtract/intersect shape composition, per-mask eye toggle & duplicate, brush-editable AI rasters with feather/expand/contract and full-resolution guided refine), crop & straighten, spot heal, reverse-fit, before/after, per-photo version snapshots and variant strips that survive a reopen (variants.json), and Ctrl+S to a Lightroom XMP. English / 中文. - Web UI —
serveopens a local gallery: pick a photo, Analyze, tweak the develop sliders (tone, presence, curves, 8-band HSL, colour grading) with live before/after, give a text direction, export. - Style retrieval — learns from similar past edits you've made (k-NN over EXIF + histogram) and offers them to the advisor as soft reference.
- Look matching (reverse-fit) —
matchtakes the same frame twice (your source and a finished rendition of it: areimagineoutput, an exported JPEG, any reference of that shot) and solves for theEditRecipethat reproduces it through the engine — CDF tone matching, then saturation, then colour cast. No pixels are copied, so the fit applies at full sensor resolution and writes recipe.json + XMP. Deterministic, no API key needed. - Generative (experimental) —
reimagine/retouchvia OpenAI Images. - Pixel retouch / Heal (experimental) — an optional mode where the AI removes
dust / blemishes / specks by healing from SURROUNDING REAL pixels
(deterministic; not generative — it invents nothing). Hybrid targeting: AI
auto-detect + paint-to-add. Writes a pixel master to
./out. - Batch the whole library, eval the AI against your own edits.
- Your library stays read-only — the engine refuses to write into a source
RAW's folder. Exports (developed/heal/retouch images) go to
./out; develop STATE (recipes, Lightroom XMP, version snapshots, mask rasters, the baked pixel-master link and the GUI's variant strip) lives in a per-user develop store (AUTOSHOP_DATA_DIR, else%LOCALAPPDATA%/autoshop/develops/<stem>-<path hash>/), so two same-named photos never collide and edits survive launching from any directory.
cargo build --release # CLI → target/release/autoshop(.exe)
cargo build --release --features gui --bin autoshop-gui # desktop app → autoshop-gui(.exe)
cargo test # unit + engine testsThe GUI sits behind the gui feature so a plain cargo build / cargo test
never pulls in eframe + winit + the GL stack. Both binaries link the same engine
library, and each tagged release ships both prebuilt for Windows.
Then any of:
- Desktop app: run
autoshop-gui(or the released.exe) and point it at a folder — the full editor, no server and no browser involved. - Web UI: double-click
Autoshop-UI.bat(Windows) — it serves your library and opens the browser. Or:autoshop serve "D:\path\to\photos" --port 8080. - CLI:
autoshop auto "photo.ARW" --guidance "warm golden-hour, lift shadows"
autoshop decode <src> # preview + EXIF + histogram
autoshop analyze <src> [--guidance "..."] # AI → recipe.json + .xmp (no render)
autoshop apply <src> <recipe.json> -o out # render a recipe to an image
autoshop auto <src> [--denoise] [--guidance "..."] # analyze + render, end-to-end
autoshop denoise <src> [--strength 0..1] [--model ...] # AI denoise → clean 16-bit master
autoshop batch <dir> [--render] [--limit N] # process a whole folder
autoshop eval <dir> [--limit N] # compare AI edits vs your own .xmp
autoshop style-index <dir> # build the "your taste" reference index
autoshop serve <dir> [--port 8080] # local web UI
autoshop reimagine <raw> --prompt "..." # experimental generative restyle
autoshop match <raw> <target> [--render] [--zoned] # reverse-fit a look → editable recipe + XMP (no key)
autoshop retouch <raw> --mask m.png --prompt "..." # experimental generative object removal
autoshop heal <src> [--mask m.png] [--no-auto] # pixel heal: spot/blemish removal (NOT generative)
autoshop recipe-schema # print the EditRecipe JSON shape
<src> is a RAW (.arw/.dng/...) or a baked image (.png/.tif/.jpg) — the
develop pipeline runs on either. RAWs also get an .xmp; baked sources get
recipe.json only (XMP is meaningful only for RAW in Lightroom).
Two roles, each configurable in the in-app Settings (⚙) panel (or via env):
| Role | What | Default | Other option |
|---|---|---|---|
| 分析 / Analysis (verifier) | data-only acceptance-check of each recipe | OAuth — the claude CLI on PATH, signed in (reuses Claude Code OAuth, no API key), model opus |
API — any OpenAI-compatible chat endpoint (base URL + key + model) |
| 图像 / Image (vision advisor) | looks at the photo → EditRecipe |
API — OPENAI_API_KEY, model gpt-5.5 |
point the base URL at any OpenAI-compatible vision endpoint. Without a key, a histogram heuristic is used. |
The claude CLI has no image input in print mode, so the image role always
speaks the OpenAI-compatible HTTP protocol. The Settings panel's "OAuth"
choice for the image role is a preset that points the endpoint at a local
subscription bridge (e.g. CLIProxyAPI) instead of a keyed API — same wire
protocol, different endpoint/credentials.
Configure keys + models from the Settings panel — written to
autoshop.local.json in your per-user Autoshop folder (never in a repo), which
overrides the environment. Keys never leave your machine: the server binds
127.0.0.1, refuses any request whose Host/Origin is not that exact
loopback authority on its own port, requires the page's per-run session
token on every state-changing request, marks all /api/* responses
no-store, never returns a key (settings answer key_present: true/false),
and sends X-Frame-Options: DENY so a page you visit cannot frame the UI.
You can also use .env:
OPENAI_API_KEY=sk-...
A settings file in the current directory is not trusted with your key.
Autoshop still reads a autoshop.local.json sitting in the folder it was
launched from — that is the pre-store layout, kept so old setups keep working —
but from v0.18.0 such a file may only choose models and providers. Its API-key
and base-URL fields are ignored, with a warning, because settings resolve per
field: a file supplying just image_base_url would have redirected the
endpoint while your real key still came from .env, and the next Analyze would
have posted that key to whoever wrote the file. Extracting a shared archive of
photos and running Autoshop inside it was enough. Your own settings, saved from
the panel into your user profile, are unaffected.
The same rule now covers two routes that were still open. Saving settings no
longer launders an ambient file into your trusted one — both settings writers
read-merge-write, so a save used to copy a planted image_base_url into your
user profile, where nothing strips it again and one ordinary "save" undid the
whole guard. And a .env may no longer choose the endpoint: dotenvy
searches the working directory and every parent, and its override mode beats
a variable you really set, so a .env dropped beside shared photos could
redirect your key exactly as the settings file could. Keys and model names from
.env still work — that is where this project's own key lives; only
AUTOSHOP_OPENAI_BASE_URL and AUTOSHOP_ANALYSIS_BASE_URL are ignored from
it, with a warning.
White balance renders slightly differently. The blackbody curve behind the Temp slider is a published piecewise fit whose branches did not meet: at 6600 K green jumped 1.31 % and blue 0.96 %, and red sat clamped flat from 6600 to 6688 K, so an 88 K band carried no temperature signal at all for the eyedropper to solve against. The branches are now rescaled to meet exactly. The cost is that white-balance gains change. Measured against a 5500 K shot, as the change in the gain each channel receives:
| Temp target | red | blue |
|---|---|---|
| 2000 K (candle — the slider's floor) | 0 % | −4.43 % |
| 2500 K | 0 % | −0.67 % |
| 3000–5000 K | 0 % | −0.32 % … −0.03 % |
| 6500 K and below | 0 % | +0.03 % |
| above 6600 K (any cool target) | +3.19 % | +2.35 % |
Red is untouched at and below 6500 K because that branch was already clamped there. The two ends move most: cool targets by the seam repair, and the very warm end because the blue branch crosses zero at 1900 K, so a small absolute change is a large relative one right at the slider's floor. Re-exports of older work at those settings will differ by that much, and this change has not had visual acceptance.
The denoiser is a small Python sidecar (python/denoise.py)
running SCUNet on the GPU. It needs Python with:
pip install torch --index-url https://download.pytorch.org/whl/cu128 # CUDA build
pip install opencv-python numpy einops requestsOn first use it downloads the model weights (~69 MB/model) into python/weights/
(gitignored). The sidecar script and its weight cache are resolved against the
program's own directory tree, never the folder you run from — a downloaded
photo pack cannot substitute its own script or weights. Trigger it via
autoshop auto --denoise, autoshop denoise <src>,
or the AI Denoise checkbox in the web UI. Models: color_real_psnr (default,
blind, best for real high-ISO/astro), color_real_gan, color_15/25/50.
The AI-provider rows below are also settable in the Settings (⚙) panel; the
per-user autoshop.local.json (in the Autoshop data folder) overrides the
environment. The two sidecar knobs (AUTOSHOP_PYTHON,
AUTOSHOP_DENOISE_MODEL) are environment-only — the panel does not carry them.
| Variable | Default | Purpose |
|---|---|---|
OPENAI_API_KEY |
— | image (vision) advisor + generative key |
AUTOSHOP_OPENAI_MODEL |
gpt-5.5 |
image/vision model id |
AUTOSHOP_OPENAI_BASE_URL |
https://api.openai.com/v1 |
image API base (any OpenAI-compatible) |
AUTOSHOP_OPENAI_IMAGE_MODEL |
gpt-image-1.5 |
generative (retouch/reimagine) model |
AUTOSHOP_ANALYSIS_PROVIDER |
oauth |
verifier provider: oauth (claude CLI) or api |
AUTOSHOP_ANALYSIS_MODEL |
opus |
verifier model (claude alias for oauth; chat id for api) |
AUTOSHOP_ANALYSIS_API_KEY |
— | verifier key when provider = api |
AUTOSHOP_ANALYSIS_BASE_URL |
https://api.openai.com/v1 |
verifier API base when provider = api |
AUTOSHOP_PYTHON |
python |
interpreter for the denoise sidecar |
AUTOSHOP_DENOISE_MODEL |
color_real_psnr |
default SCUNet weights |
- Render ops are tasteful approximations of Lightroom, not bit-exact. The XMP→Lightroom path renders them faithfully in the meantime.
- AI denoise runs on the demosaiced RGB (not the raw Bayer mosaic like Adobe Denoise), and ~3 min for a 60 MP frame on an RTX 4060 Ti. Excellent, not identical to Adobe.
- Kelvin white balance is absolute only on a RAW, where the as-shot temperature is read from the camera metadata and stamped into the develop. A baked PNG/TIFF has no as-shot reading, so the same slider anchors at 5500 K and acts as a relative shift from there — it moves pixels, it just cannot claim to be the scene's true colour temperature.
- Generative
reimagineis a low-res, lossy re-render — an experiment, not a master.retouch(generative fill) regenerates only the masked region and composites it back onto the source's own develop with a feathered seam, so the rest of the frame keeps the original pixels. That base is the engine's own neutral develop — capped at 2048 px on the long edge by default — never the camera's embedded JPEG, so the composite stays on the same tone chain as the canvas. A baked PNG/TIFF is likewise thumbnailed to 2048 px. Pass--full-res(CLI) or tick Full-res (UI) to composite at full resolution instead (~60 MP for a RAW; slow — only the small removed patch is upscaled). Both pick an aspect-correct size (no square-squash) and default toquality=high(override--quality). - Pixel heal (
autoshop heal/ the UI's 去瑕疵 panel) is the non-generative retoucher: it removes only SMALL defects (dust / blemishes / specks) by sampling surrounding REAL pixels — it never invents content. Best on fairly uniform backgrounds (sky, skin, wall, water); busy backgrounds heal approximately. AI auto-detection needs the vision key; the paint-a-mask path works offline. Runs on a ≤2048 px base by default — the engine's own neutral develop for a RAW, the source thumbnailed for a baked image;--full-resheals at full resolution instead (slow), on either source type.
Rust (rustc/cargo 1.94) · rawler (Sony ARW decode) · image · rayon ·
clap · serde · ureq · eframe/egui (desktop GUI) · tiny_http (web UI) ·
Python + PyTorch + SCUNet (denoise) · Claude CLI (verifier) ·
OpenAI Responses + Images (advisor + generative).
See docs/ARCHITECTURE.md for the full design.
