pipic CLI · AI-native

Compress images with one command.

The same engine as the website, in your terminal, your build and your agent. Node 20 or newer, no telemetry, images deleted the moment they’re compressed.

100images / month free
5,000on Pro
Claude CodeCodexCursor+70

Let your agent install it

Send this to Claude Code, Codex or any coding agent — it reads this doc and sets itself up.

Install the pipic CLI for me based on this doc, then tell me how to sign in: https://pipic.cc/cli

Why the CLI

Agent-native output

NDJSON and stable exit codes an agent can branch on — not prose it has to guess at.

Whole folder, one command

In place or into a fresh directory — local batches and build output alike.

Sign in once

Scripts, CI (via PIPIC_TOKEN) and agents run unattended after that — nothing to approve again.

Safe by default

Nothing is touched without an explicit --replace or -o, writes are atomic, and files that wouldn’t shrink are left alone.

Quick start

agents · install the skill

Install the skill once and your agent finds pipic on its own — you never have to name the tool or repeat the flags again.

1

Install the CLI

Node 20 or newer
$ npm i -g @pipic/cli
Prefer not to install globally? npx @pipic/cli <paths…> works the same way.
2

Install the skill

Claude Code, Codex, Cursor and 70-odd others
$ npx skills add PiPic-cc/pipic-cli -g
npx skills add PiPic-cc/pipic-cli -g -a claude-code -a codex -a cursor -y
The bare command asks which agents to install into; the flags above skip that prompt. npx skills update refreshes it later.
3

Approve the sign-in

One approval per machine
$ pipic login
Opening your browser…
✓ Signed in as you@example.com
On the first request the agent walks you through pipic login — a browser link, or a device code when it’s headless. It never signs in on your behalf, and the saved credential covers every later run.
4

Then just ask

No tool name, no flags
“Compress the images in ./assets.”
“These screenshots are huge — shrink them in place.”
“Optimise everything in public/ before the build.”
What the skill teaches your agent
  • Never run pipic login itself — hand the approval to the user.
  • skipped is not a failure — it carries the reason, e.g. already small enough.
  • After a partial failure, re-run only the failed files — a full re-run spends quota twice.
No skill support? Paste instead

One-off task, or an agent without skills — hand it the command directly. The full contract lives one section down:

Use the pipic CLI to compress the images in ./assets, replacing them in place:

  pipic ./assets --replace --json

Run `pipic -h` for more.
See the full contract →

Agent running in a container or sandbox that can’t see your ~/.config? Create a token on your account page and set PIPIC_TOKEN in that environment instead.

Running it yourself

humans · scripts · CI

Install

Node 20 or newer
$ npm i -g @pipic/cli
$ pipic login
Opening your browser…
✓ Signed in as you@example.com
One global install and one browser approval — every later run, in any shell, is already signed in.

Nothing installed

npx
npx @pipic/cli ./assets --replace
Works without a global install — it still needs the one-time pipic login.

No browser — SSH, containers

device code
$ pipic login --no-browser
Open https://pipic.cc/cli/authorize
Enter this code: PXBQ-GTZM
Expires in 10 minutes · waiting…
Headless environments switch to the device-code flow automatically — approve it from any other device.

CI and sandboxes

PIPIC_TOKEN
export PIPIC_TOKEN=pipic_xxx
Takes priority over the credentials file. Tokens are created and revoked on your account page — never minted by the CLI.

Commands

pipic <paths…>Compress files or a directory. This is the default command.
pipic login [--no-browser]Authorize this machine through the browser, or with a device code.
pipic logoutSign out and revoke this machine’s token.
pipic whoamiShow the signed-in account and its plan.
pipic quotaShow how much of this month’s quota is left.
pipic token listList your tokens with their prefix and last use.
pipic token createPrints a link to create one on the website — for security, creating a token always happens there, never in the CLI.
pipic token revoke <id>Revoke a token you own, usually effective within a minute.

login, logout, whoami, quota and token are matched as subcommands before pipic treats them as paths. To compress a folder that happens to share one of those names, write ./login or login/ — anything with a path separator goes to the compress command instead.

Compress options

--replace

Overwrite the originals in place — atomic replace, permissions kept, symlinks resolved.

-o, --out <dir>

Write results to this directory instead.

--json

NDJSON output, one line per file — for scripts and agents.

--concurrency <n>

Parallel uploads. Default 4.

You must give exactly one of --replace or -o — they’re mutually exclusive, and neither is a default. Without one, pipic exits with a usage error (code 2).

Good to know

  • Files are only written back when the result is actually smaller — already-optimized images are skipped, with the reason reported. Under -o the original is copied across anyway, so the output directory is always a complete set.
  • --replace writes to a temp file and renames it, so a Ctrl-C never leaves a half-written file behind.
  • Files over 8 MB are skipped with a clear reason, never silently dropped.
  • JPG, PNG, WebP and AVIF are supported. No telemetry is ever sent.
  • With -o, two files that share a name — from different subfolders, say — collide: pipic reports an error for both rather than guessing which one to keep.

JSON Output Contract

--json prints one JSON object per line, one per file, with six fixed fields:

$ pipic ./assets --json --replace
{"file":"/p/hero.png","status":"ok","before":2411233,"after":486201,"saved":1925032}
{"file":"/p/notes.txt","status":"skipped","before":0,"after":0,"saved":0,"error":"unsupported file type"}
fileThe path you passed in, unchanged.
status"ok", "skipped", or "error" — no other values.
beforeOriginal size in bytes.
afterCompressed size in bytes — 0 on skipped/error rows.
savedBytes saved (before minus after) — never a percentage.
errorPresent on skipped and error rows only — a human-readable reason, not a code.

Exit codes

0All files succeeded
1Some files failed
2Usage error
3Sign-in required
4Quota exhausted

This is a stable contract: branch scripts and agents on status and the exit code — never on the text of error.

HTTP API

No Node? Call the same compression engine directly over HTTP — one image per request, no SDK, no multipart forms.

POSThttps://pipic.cc/compress/image
Request
AuthorizationBearer <token> — required on every request.
Content-Typeimage/png, image/jpeg, image/webp or image/avif — required, and must match the bytes you send.
X-Original-NameOptional. URL-encode the filename first — only encodeURIComponent-safe characters are echoed back.
BodyRaw image bytes, not multipart/form-data. One image per request, up to 8 MB.
$ curl -X POST https://pipic.cc/compress/image \
  -H "Authorization: Bearer $PIPIC_TOKEN" \
  -H "Content-Type: image/png" \
  --data-binary @photo.png \
  -o photo-compressed.png
200 OK · same format in, same format out

Response

200 OK returns the compressed image as the response body — same format in, same format out. Content-Type reflects the compressed format; Content-Length and X-Original-Name come back too when available.

Get a token

The API uses the same Personal Access Tokens as the CLI. Sign in with GitHub or Google, then create one from your account page — the plain token is shown once, so save it somewhere safe.

Create a token

Errors

Anything other than 200 responds with a JSON envelope. Branch your code on the code field, not on the message text — here’s a real one:

{"success":false,"code":"MONTHLY_QUOTA_EXCEEDED","message":"Monthly compression quota reached, try again next month"}
400INVALID_TYPE — missing or non-image Content-Type; NO_FILE — empty body
401UNAUTHORIZED, TOKEN_EXPIRED or TOKEN_REVOKED — sign in again or create a new token
413FILE_TOO_LARGE — over 8 MB
415UNSUPPORTED_TYPE — an image/* type we don’t compress (only PNG, JPEG, WebP, AVIF)
429RATE_LIMITED (see the Retry-After header) or MONTHLY_QUOTA_EXCEEDED — this month’s allowance is used up
502UPSTREAM_ERROR — our compression backend rejected this image; retrying the same bytes fails the same way. The attempt is refunded to your quota
503UPSTREAM_ERROR or ALL_KEYS_EXHAUSTED — temporarily out of capacity; safe to retry with backoff. The attempt is refunded to your quota

Good to know

  • A request counts against your quota the moment we accept it for compression — including ones that go on to fail with 400, 413 or 415. Requests rejected before that point never count: any 401, a 429 RATE_LIMITED, and a file rejected purely on its declared Content-Length header. If we fail on our side (502/503), the attempt is refunded automatically.

Every header and error code, in one machine-readable file: /openapi.json

FAQ

Will an agent touch files I didn’t tell it to?

No — pipic requires an explicit --replace or -o <dir>. Without one it refuses to run, and it never sends a single request before reporting that error.

I signed in once — can an agent keep using pipic forever?

Yes. The credential lives on this machine at ~/.config/pipic/config.json, and any tool running as you can read it — no extra approval needed per agent.

An agent says it’s not signed in — what do I do?

It’s most likely running in a container or sandbox that can’t see your ~/.config. Create a token on your account page and set it as PIPIC_TOKEN in that environment.

What happens when the free quota runs out?

pipic exits with code 4 and nothing is ever charged automatically. Free includes 100 images a month; Pro raises that to 5,000.

Are my images kept anywhere?

No — they’re deleted from the server the moment compression finishes, and nothing is stored long-term.

Compress 100 images a month, free.

No card, no telemetry, and the browser tool stays unlimited.

Sign in to get a token