
May 09, 20263 min read
I kept paying $7/month to compress images on a machine that wasn’t mine, using a machine I already owned that was sitting right there.
It started with a client site audit. I was looking at a WordPress media library with about 400 images – a mix of product photos, blog headers, and team headshots – and the Smush dashboard was cheerfully telling me 300 of them were “unoptimized.” The free tier wouldn’t touch WebP conversion. The EWWW option wanted shell access the host had disabled. ShortPixel was going to cost credits I’d have to keep buying. All of this to compress files on a server in a data center using tools I didn’t control.
My laptop was sitting right there. It’s an M2 Mac. It can remove image backgrounds in two seconds. I started thinking about what a local-first WordPress media tool would actually look like, and a few months later that became localPress.
The incumbent tools split into two camps. Cloud services (ShortPixel, Imagify, Smush Pro, Optimole) do the processing on their servers and charge you monthly for the privilege. EWWW does local processing, but “local” means the web server – and it needs exec() and shell access that shared hosts frequently block.
Nobody was combining WordPress-awareness + processing on the user’s actual machine + a proper CLI + round-trip desktop editor integration. That’s the gap localPress fills.
localPress connects to any WordPress site via Application Passwords – built into WP core since 5.6, no plugin required. Once connected, it pulls attachment metadata, runs processing locally, and pushes results back via the REST API. The architecture is straightforward:
localpress CLI (TypeScript + Bun)
Engine: sharp + jSquash WASM + ONNX Runtime
State: SQLite per-site databases
Auth: WordPress Application Passwords
-> RestAdapter (always available)
-> WpCliAdapter (SSH, optional)The CLI is built on Bun and ships as a single binary for macOS (arm64/x64) and Linux (arm64/x64). Install via Homebrew or download a release binary directly.
There are 15 commands across five categories. A typical session looks something like this:
# 1. Connect to a site (interactive Ink wizard)
localpress init
# 2. Audit the library - find the actual waste
localpress audit
# 45 unoptimized, 12 oversized for display, 23 missing alt text, 3 duplicates
# 3. Optimize everything unprocessed
localpress optimize --unoptimized --apply
# 4. Right-size the oversized ones
localpress resize 101 102 103 --max-width 1920
# 5. Remove a background locally - no credits, no cloud
localpress remove-bg 456
# 6. Open in your real editor, watch for saves, auto-sync
localpress edit 456 --with "Photoshop"
# 7. Check where an image is used before touching it
localpress references 789A few behaviors I wanted to get right from the start: bulk operations dry-run by default (pass --apply to execute), re-running optimize on an already-processed image is a no-op via SHA-256 hash comparison, and localPress references tells you every post and page using an attachment before you make any changes.
This one took some work. localPress remove-bg runs U2-Net segmentation models via ONNX Runtime, entirely on your machine. The models download once on first use – u2net is ~176MB and gives you the best results, silueta is ~44MB for a balanced option, and u2netp is ~4.7MB if you need something fast. You can also shell out to system Python’s rembg via --rembg if you already have that set up.
On an M2, the processing takes about 1.5 seconds per image. ShortPixel charges 1 credit per removal. On a library of a few hundred product photos, that math gets interesting pretty quickly.
The edit command is the one I’m most happy with. It downloads the attachment to a temp file, opens it in whatever desktop app you specify, watches the file for changes using chokidar, and uploads any saves back to WordPress automatically. You keep your real tools – GIMP, Photoshop, Preview, Affinity, whatever – and the sync happens in the background.
localpress edit 456 --with "Photoshop"
# Opens attachment #456 in Photoshop
# Watching for saves...
# [save detected] Uploading changes to WordPress...
# Done.No other WordPress media tool I’ve found offers this workflow. It’s one of those things that feels obvious once you see it, but nobody had built it.
localPress ships with a companion skill (skill/SKILL.md) that teaches AI agents how to drive the CLI. The design goal was composability: if you already have a WordPress MCP server configured (say, the one I use on this site), localPress adds local processing capabilities on top of it rather than replacing the integration layer you already have.
In practice this means an agent can look up an attachment ID via your existing MCP tools, pass it to localpress remove-bg or localpress optimize, and the results sync back to WordPress automatically. No new protocol code, no competing integration.
The 1.x releases shipped pretty quickly after the foundation was stable. The full feature set now includes the interactive init wizard (Ink-powered), jSquash WASM codecs for OxiPNG-level PNG compression, advanced audit modes, configuration profiles for different optimization presets, doctor --fix for auto-remediation, and the Homebrew tap for easy installation.
A few things are still on the roadmap: a self-update command, AI-powered alt-text generation using local vision models, a continuous directory watch mode, and a cumulative savings dashboard. Full list at https://github.com/gfargo/localpress/issues.
# Homebrew (macOS / Linux)
brew install gfargo/localpress/localpress
# Or download a binary from GitHub Releases
# https://github.com/gfargo/localpress/releases
# Or run from source (requires Bun >= 1.1.0)
git clone https://github.com/gfargo/localpress.git
cd localpress && bun install && bun run dev -- --helpOnce installed, run localpress init to connect your first site and localpress audit to get a picture of your media library. The project page has the full overview: /project/localpress/.
If you give it a try and run into something broken or something missing, open an issue on GitHub – I’m actively working through the roadmap. Curious what workflows other folks are running their WordPress media through.
Discussion
Comments are powered by Disqus. Sign in once, comment anywhere.
