What it does
SHIFT sits between your application and the model API. Every request passes through a pipeline that inspects, evaluates, and transforms media inputs so they conform to provider constraints.
Before SHIFT: oversized images, unsupported formats, and bloated payloads cause hard failures (400 errors, token waste, session crashes).
After SHIFT: every request is valid, optimized, and tuned to your cost/quality preference.
Token savings
SHIFT estimates per-provider token savings for every run. Both OpenAI and Anthropic charge tokens based on image dimensions — resizing images before they hit the API reduces cost.
| Scenario | Before | After | OpenAI tokens | Anthropic tokens |
|---|---|---|---|---|
| 4000×3000 hero image (balanced) | 4000×3000 | 2048×1536 | 765 → 765 | 1,568 → 1,568 |
| 4000×3000 hero image (economy) | 4000×3000 | 1024×768 | 765 → 765 | 1,568 → 1,082 (−31%) |
| 1254×1254 app icon (economy) | 1254×1254 | 1024×1024 | 765 → 765 | 1,568 → 1,405 (−10%) |
| SVG diagram → rasterized PNG | SVG | 512×256 PNG | 255 → 255 | 0 → 98 |
Token estimates based on published provider formulas. OpenAI uses tile-based counting (GPT-4o/4.1 family, 512×512 tiles); Anthropic uses pixel-based (w×h/750, 1568px long-edge cap for standard models). Actual billing may vary by model — newer OpenAI models use patch-based counting, and Anthropic Opus 4.7 supports higher resolution (2576px, 4784 max tokens).
Sample report
$ cat request.json | shift -m economy -o report
=== SHIFT Report ===
Images found: 1
Images modified: 1
Images dropped: 0
Original size: 42262 bytes
Transformed size: 17018 bytes
Size reduction: 59.7%
Token Savings (estimated):
OpenAI: 765 -> 765 tokens (0.0% saved)
Anthropic: 1,568 -> 1,082 tokens (31.0% saved)
Per-image breakdown:
[0] 4000x3000 -> 1024x768 (OpenAI: 765 -> 765, Anthropic: 1,568 -> 1,082)
Actions:
[image 0] resize — 4000x3000 -> 1024x768
Cumulative tracking
SHIFT automatically records run statistics to ~/.shift/stats.jsonl. View cumulative savings with shift gain:
$ shift gain
=== SHIFT Cumulative Savings ===
Runs: 42
Images: 156 processed, 89 modified
Bytes: 247.3 MB saved
Token Savings (estimated):
OpenAI: 52,400 -> 12,300 tokens (76.5% saved)
Anthropic: 84,200 -> 28,100 tokens (66.6% saved)
$ shift gain --daily
=== SHIFT Daily Token Savings ===
Date Runs Images OpenAI saved Anthropic saved
----------------------------------------------------------
2026-04-20 8 24 3,200 5,400
2026-04-21 12 42 4,800 8,200
2026-04-22 22 90 12,100 18,500
Use shift gain --format json for machine-readable output.
Install
From crates.io
From GitHub (latest)
From source
Build without installing
# Binary at target/release/shift
Pre-built binaries
Download from GitHub Releases — macOS (x86/arm) and Linux (x86/arm).
Verify installation
# Quick validation — transform a sample payload
|
# Check stats tracking
Quick start
# Transform an OpenAI request (stdin/stdout pipe)
|
# Transform an Anthropic request from a file
# See what would change without modifying anything
# Compose with curl
|
Options
shift [OPTIONS] [FILE]
Arguments:
[FILE] Input file (JSON request payload). Reads stdin if omitted.
Options:
-p, --provider <PROVIDER> Target provider [default: openai]
[openai, anthropic, claude]
-m, --mode <MODE> Drive mode [default: balanced]
[performance, balanced, economy]
--svg-mode <MODE> SVG handling [default: raster]
[raster, source, hybrid]
-o, --output <FORMAT> Output format [default: json]
[json, report, json-report, both]
--dry-run Show what would change without modifying
--profile <FILE> Custom provider profile JSON
--model <MODEL> Target model (overrides model in payload)
--no-stats Disable saving run statistics
-v, --verbose Verbose output
Commands:
shift gain Show cumulative token savings
shift gain --daily Day-by-day breakdown
shift gain --format json Machine-readable output for dashboards
Drive modes
| Mode | What it does |
|---|---|
| performance | Minimal transforms. Only enforce hard provider limits (max dimension, max file size). Preserve original fidelity. |
| balanced | Moderate optimization. Resize oversized images, recompress bloated files. Remove obvious waste. Default. |
| economy | Aggressive optimization. Downscale everything to 1024px, drop excess images beyond provider limits, minimize token usage. |
SVG handling
Most AI model APIs reject SVG. SHIFT detects SVG inputs and handles them based on --svg-mode:
| Mode | Behavior |
|---|---|
| raster | Rasterize SVG to PNG via resvg (default, provider-safe) |
| source | Replace the image with SVG XML as a text content block |
| hybrid | Rasterize to PNG and retain SVG source as text |
Supported formats
Detected and processed:
| Category | Formats |
|---|---|
| Raster images | PNG, JPEG, GIF, WebP, BMP, TIFF |
| Vector images | SVG (auto-rasterized to PNG) |
| Encodings | base64 data URIs, raw base64, URL references |
BMP and TIFF are auto-converted to PNG. SVGs are rasterized. Everything else passes through if it meets provider constraints.
Provider profiles
Built-in constraints for the two major multimodal providers:
| Provider | Max images | Max dimension | Max file size | Megapixel limit |
|---|---|---|---|---|
| OpenAI | 10 | 2048 px | 20 MB | -- |
| Anthropic | 20 | 8000 px | 5 MB | 1.15 MP |
Profiles include per-model overrides (gpt-4o, gpt-4.1, claude-sonnet-4, etc.) and fall back to provider defaults for unknown models.
Custom profiles can be loaded with --profile custom.json.
Library usage
SHIFT is split into two crates: shift-preflight (library) and shift-preflight-cli (binary). The library can be used directly in Rust applications:
# Cargo.toml
[]
= "0.1"
use ;
use json;
let payload = json!;
let config = ShiftConfig ;
let = process.unwrap;
eprintln!; // what changed and why
How it works
-
Inspect -- Detect every image in the request payload. Extract format (via magic bytes), dimensions, file size, encoding type. Handles base64 data URIs, raw base64, and URL references (fetched automatically).
-
Evaluate -- Load the provider profile for the target API. Compare each image's metadata against the constraints. Apply mode-specific rules to determine what actions are needed (resize, recompress, convert, rasterize, drop).
-
Transform -- Execute the actions. Resize preserves aspect ratio using Lanczos3 filtering. SVGs are rasterized with
resvg(supports gradients, text, viewBox). BMP/TIFF are converted to PNG. JPEG recompression uses mode-tuned quality levels. -
Reconstruct -- Rebuild the original payload with transformed images slotted back in. Output is a valid JSON request ready to send to the API.
Project structure
shift/
├── shift-core/ Library crate: shift-preflight (all processing logic)
│ └── src/
│ ├── inspector/ Format detection, metadata extraction
│ ├── policy/ Provider profiles, constraint evaluation, rules
│ ├── transformer/ Image resize, recompress, SVG rasterize, convert
│ ├── payload/ OpenAI + Anthropic message format parse/reconstruct
│ ├── pipeline.rs Orchestrator: inspect -> policy -> transform
│ ├── cost.rs Token estimation (OpenAI tile, Anthropic pixel)
│ ├── stats.rs Persistent run statistics, gain summaries
│ ├── report.rs Transformation report with token savings
│ └── mode.rs DriveMode, SvgMode, ShiftConfig
├── shift-cli/ Binary crate: shift-preflight-cli (CLI + gain subcommand)
├── profiles/ Provider constraint JSON (embedded at compile time)
├── tests/
│ ├── fixtures/ Test images and sample payloads
│ └── docker/ Dockerfiles for cross-distro CI (Ubuntu, Arch)
└── .github/workflows/ CI + Linux distro tests
Roadmap (v2+)
- Video: frame sampling, keyframe extraction, resolution downscale
- Audio: compression, transcription to text
- Documents: chunking, summarization, text extraction
- Smart image selection: near-duplicate detection, keep most informative
- Caption fallback: replace low-value images with text descriptions
- Adaptive policies: dynamic adjustment based on request size and latency targets
License
Apache-2.0