RepoPilotOpen in app →

h2non/imaginary

Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 6mo ago
  • 34+ active contributors
  • Distributed ownership (top contributor 42% of recent commits)
Show all 7 evidence items →
  • MIT licensed
  • CI configured
  • Tests present
  • Slowing — last commit 6mo ago

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/h2non/imaginary)](https://repopilot.app/r/h2non/imaginary)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/h2non/imaginary on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: h2non/imaginary

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/h2non/imaginary shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 6mo ago
  • 34+ active contributors
  • Distributed ownership (top contributor 42% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Slowing — last commit 6mo ago

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live h2non/imaginary repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/h2non/imaginary.

What it runs against: a local clone of h2non/imaginary — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in h2non/imaginary | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 210 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>h2non/imaginary</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of h2non/imaginary. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/h2non/imaginary.git
#   cd imaginary
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of h2non/imaginary and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "h2non/imaginary(\\.git)?\\b" \\
  && ok "origin remote is h2non/imaginary" \\
  || miss "origin remote is not h2non/imaginary (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "imaginary.go" \\
  && ok "imaginary.go" \\
  || miss "missing critical file: imaginary.go"
test -f "server.go" \\
  && ok "server.go" \\
  || miss "missing critical file: server.go"
test -f "controllers.go" \\
  && ok "controllers.go" \\
  || miss "missing critical file: controllers.go"
test -f "image.go" \\
  && ok "image.go" \\
  || miss "missing critical file: image.go"
test -f "source.go" \\
  && ok "source.go" \\
  || miss "missing critical file: source.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 210 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~180d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/h2non/imaginary"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

imaginary is a fast, stateless HTTP microservice written in Go for high-level image processing, backed by libvips (C library). It exposes image operations like resize, crop, rotate, and format conversion via simple REST endpoints, supporting JPEG, PNG, WEBP, HEIF, and optionally TIFF, PDF, GIF, and SVG. It can read images from POST payloads, local filesystem, or remote HTTP servers, and is Docker-native with first-class Fly.io and Cloud Run support. Monolithic service architecture: imaginary.go is the main entry point; controllers.go routes HTTP endpoints to image operations; image.go contains core processing logic using bimg; source_*.go (source_body.go, source_fs.go, source_http.go) abstract three image input methods; middleware.go handles CORS, auth, throttling; error.go, health.go, log.go provide cross-cutting concerns. No package structure—all files in root with _test.go pairs for unit tests.

👥Who it's for

DevOps engineers and backend teams building scalable image processing pipelines who need a lightweight, dependency-free microservice they can deploy in containers. Also platform engineers needing to offload image transformation from application servers without complex ImageMagick/GraphicsMagick infrastructure.

🌱Maturity & risk

Production-ready. The codebase is well-structured with 122KB of Go code, comprehensive unit tests across all modules (error_test.go, health_test.go, image_test.go, server_test.go, etc.), CI via Travis CI (.travis.yml), and deployment configs for Docker, Fly.io, and Cloud Foundry. The project has active Docker Hub presence (referenced badges show pull counts) suggesting real-world usage.

Low risk overall, but single-maintainer (h2non) creates sustainability concerns. Dependency footprint is minimal (bimg, filetype, cors, throttled/v2) reducing supply-chain risk. Go's stability and static binary compilation mitigate versioning issues. Requires libvips with specific version (8.3+) compiled with optional bindings for advanced formats (TIFF, PDF, GIF, SVG), which can complicate deployment if those features are needed.

Active areas of work

No recent commit data visible in the provided repo metadata, so current activity level is unclear. The presence of .devcontainer/ and devcontainer.json suggests recent modernization for containerized development. Fly.io launch badge in README indicates active platform support updates.

🚀Get running

git clone https://github.com/h2non/imaginary.git
cd imaginary
make build
./imaginary -p 9000

Or Docker: docker run -p 9000:9000 h2non/imaginary:latest. Requires Go 1.12+ and libvips (libvips-dev on Debian/Ubuntu, vips on macOS).

Daily commands:

make build          # Compiles Go binary
make run            # Runs server on default port (see Makefile)
make test           # Runs unit tests
./imaginary -p 8080 -a 127.0.0.1  # Custom port and bind address

For Docker: docker-compose up (docker-compose.yml provided).

🗺️Map of the codebase

  • imaginary.go — Main entry point and server initialization; defines the core Imaginary application struct and startup logic
  • server.go — HTTP server setup and request routing; registers all API endpoints and middleware chains
  • controllers.go — Core image operation handlers (resize, crop, rotate, etc.); implements the primary business logic for all image transformations
  • image.go — Image abstraction layer wrapping bimg; provides normalized interface for all image processing operations
  • source.go — Abstract image source interface; enables pluggable source backends (HTTP, filesystem, request body)
  • middleware.go — Request middleware including authorization, throttling, CORS, and signature validation
  • go.mod — Declares bimg/libvips dependency and Go version; critical for understanding image processing backend

🧩Components & responsibilities

  • Image Source Abstraction (Go io.Reader, net/http client) — Fetches or reads image bytes from various origins (HTTP, filesystem, request body) and detects format
    • Failure mode: Returns error if source unreachable, format unsupported, or timeout; caller receives 400/503 response
  • Image Processor (bimg wrapper) (bimg (C bindings to libvips)) — Parses image, applies transformations (crop, resize, rotate, filter), and encodes to target format
    • Failure mode: libvips errors bubble as 400/422 responses; OOM/segfault crashes entire server process
  • Middleware Pipeline (net/http handlers, throttled/v2) — Enforces security (auth tokens, HMAC signatures), rate limiting, CORS, and error recovery
    • Failure mode: Rejected requests return 401/403/429; panics caught and logged as 500
  • HTTP Router & Controllers (net/http ServeMux, custom routing) — Maps incoming requests to image operations; parses query parameters and coordinates request flow
    • Failure mode: Unsupported routes return 404; invalid params return 400; panics converted to 500

🔀Data flow

  • HTTP ClientHTTP Server (net/http) — POST/GET request with image bytes (body or URL) and operation parameters (query string)
  • `` → undefined — undefined

🛠️How to make changes

Add a new image operation endpoint

  1. Define the operation function in controllers.go (e.g., func (o *Operation) MyOperation(c *Context) error) (controllers.go)
  2. Add query parameter parsing logic in params.go for any new parameters (params.go)
  3. Implement the image transformation in image.go by calling bimg methods on the Image struct (image.go)
  4. Register the HTTP route in server.go in the main route setup function (server.go)
  5. Add unit tests following the existing test_test.go naming pattern (controllers_test.go)

Add a new image source backend

  1. Create a new source implementation file (e.g., source_custom.go) implementing the Source interface from source.go (source.go)
  2. Implement the Source interface methods (Read, ImageType, Close) with your custom image loading logic (source_custom.go)
  3. Update server.go to instantiate your source based on request type or configuration (server.go)
  4. Add tests following the source_*_test.go naming pattern (source_custom_test.go)

Add new middleware (auth, throttle, validation)

  1. Implement your middleware function in middleware.go following the net/http middleware pattern (middleware.go)
  2. If needed, add configuration options to options.go (options.go)
  3. Register the middleware in server.go in the appropriate position in the middleware chain (server.go)
  4. Add unit tests in middleware_test.go (middleware_test.go)

🔧Why these technologies

  • Go + net/http — Lightweight concurrency model with goroutines; zero-dependency HTTP server for minimal footprint and high throughput
  • bimg + libvips — Industry-standard image processing library with SIMD optimizations; handles 20+ image formats with fast in-memory transformations
  • Docker containerization — Reproducible deployment; libvips system dependencies bundled; scales horizontally via orchestration platforms
  • HMAC-SHA256 signatures — Stateless URL verification without server-side storage; prevents unauthorized image processing requests

⚖️Trade-offs already made

  • No-framework HTTP server (native net/http)

    • Why: Faster request/response cycles and lower memory overhead than frameworks like Gin or Echo
    • Consequence: More boilerplate for middleware chaining; manual route registration
  • Stateless architecture; no caching layer

    • Why: Simplifies deployment and horizontal scaling; images are already compressed outputs
    • Consequence: Repeated requests for identical images re-process; caller responsible for HTTP caching headers
  • Synchronous request-response model

    • Why: Simple API contract; matches HTTP semantics for image operations
    • Consequence: Large images or complex operations block until complete (~100-500ms); no async job queues
  • In-process image processing (no queue/worker separation)

    • Why: Lower latency; no inter-process communication overhead
    • Consequence: Server process ties up on CPU-intensive transforms; single server capacity limited by CPU cores

🚫Non-goals (don't propose these)

  • Real-time image processing with WebSocket streams
  • User authentication/authorization management (only HMAC signatures and API tokens for access control)
  • Distributed batch image processing or job queues
  • Persistent image storage or CDN integration
  • GUI image editor or interactive cropping interface

🪤Traps & gotchas

libvips version lock: Optional image formats (TIFF, PDF, GIF, SVG) require libvips 8.3+ compiled with specific library bindings—missing bindings silently disable features. Placeholder fallback mode: When enabled (see placeholder.go), returns generated placeholder images on error instead of HTTP error status—can mask upstream failures in production. BIMG_CONCURRENCY_LEVEL: Not exposed as CLI flag; libvips internal concurrency must be tuned via environment or recompilation for high-throughput scenarios. URL signature validation: Requires shared secret between client and server; no key rotation mechanism visible—compromised secrets cannot be revoked mid-deployment. No graceful shutdown: Appears to lack timeout-aware request draining in server.go—abrupt container kills during slow image processing may corrupt output.

🏗️Architecture

💡Concepts to learn

  • Functional Options Pattern — imaginary uses functional options (options.go) to configure server behavior without breaking API changes; critical pattern for extending features like API tokens, throttling, and CORS
  • Middleware Chain (HTTP) — middleware.go implements handler chaining for cross-cutting concerns (auth, logging, throttling); understanding this is essential for adding new request/response processing
  • Token Bucket Rate Limiting — imaginary supports token bucket throttling (via throttled/v2 dependency) to prevent resource exhaustion; production deployments must understand this to set appropriate limits
  • HMAC URL Signature Verification — imaginary can validate requests via HMAC-signed URLs (mentioned in options.go) to prevent unauthorized image transformations; critical security feature for public-facing deployments
  • Source Abstraction (Interface Segregation) — source.go defines a minimal Reader interface allowing pluggable sources (POST body, filesystem, HTTP); demonstrates Go interface design for extensibility
  • Image Format Negotiation (Content Negotiation) — imaginary auto-detects and converts between JPEG, PNG, WEBP via filetype library and output parameters; understanding format trade-offs (quality, size, transparency) is essential
  • Memory-Efficient Image Processing — libvips (and by extension imaginary) uses streaming decompression to minimize memory footprint—critical for serverless and resource-constrained deployments; referenced in README benchmarks
  • h2non/bimg — Direct dependency: low-level Go wrapper around libvips that imaginary builds on top of
  • libvips/libvips — Upstream C library providing the actual image processing engine; understanding libvips limitations and capabilities directly impacts imaginary behavior
  • willnorris/imageproxy — Alternative lightweight Go image proxy/processor that uses native image/jpeg instead of libvips; trade-off study for use-case fit
  • davidbyttow/govips — Competing Go wrapper around libvips with different API design; reference for alternative architectural choices
  • fly-apps/imaginary — Official Fly.io deployment template for imaginary; shows production deployment patterns and configuration best practices

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive integration tests for HTTP source handler (source_http.go)

source_http.go handles fetching images from remote URLs, which is a critical security and reliability concern. Currently, source_http_test.go exists but likely lacks coverage for edge cases like timeout handling, redirect chains, SSL/TLS validation, malicious content-type headers, and connection pooling. This is high-value because remote image fetching is a common attack vector and performance bottleneck in image microservices.

  • [ ] Review source_http_test.go for gaps in test coverage
  • [ ] Add tests for HTTP timeout scenarios with configurable timeouts
  • [ ] Add tests for redirect chain handling (max redirects)
  • [ ] Add tests for content-type validation and image format verification
  • [ ] Add tests for SSL/TLS certificate validation and error handling
  • [ ] Add tests for concurrent requests and connection pooling behavior

Add GitHub Actions CI workflow for multi-architecture Docker builds

.travis.yml exists but Travis CI is deprecated. The repo has full Docker support (Dockerfile, docker-compose.yml, .devcontainer) but no modern GitHub Actions workflow for automated multi-architecture (amd64, arm64, arm32) image building and pushing. This is valuable because h2non/imaginary is a popular Docker image on Docker Hub, and contributors need CI validation for Dockerfile changes across architectures before merging.

  • [ ] Create .github/workflows/docker-build.yml workflow file
  • [ ] Add steps for building with docker/setup-buildx-action for multi-arch support
  • [ ] Add conditional step to push to Docker Hub only on main branch with proper tagging
  • [ ] Add step to test built image with basic health checks (reference health_test.go patterns)
  • [ ] Document the workflow in README.md's Docker section

Add missing test coverage for middleware.go and add request/response validation tests

middleware.go is referenced in the file list but has no corresponding middleware_test.go file. Middleware typically handles CORS (rs/cors dependency is present), rate limiting (throttled dependency is present), and request validation. Without tests, changes to request parsing, error handling, or middleware ordering can break the API contract unexpectedly. This is high-value for API stability.

  • [ ] Create middleware_test.go with test suite structure
  • [ ] Add tests for CORS middleware behavior using the rs/cors dependency
  • [ ] Add tests for rate limiting/throttling via throttled/v2 dependency with concurrent requests
  • [ ] Add tests for invalid request parameter handling (referencing params.go test patterns)
  • [ ] Add tests for middleware chain ordering and error propagation
  • [ ] Add tests for security headers and content-type validation in responses

🌿Good first issues

  • Add unit tests for placeholder.go—file exists but has no corresponding placeholder_test.go file; could add test coverage for fallback image generation and error serialization in HTTP headers.
  • Document required libvips compile flags for optional formats in README.md—users enabling TIFF/PDF/GIF/SVG support get silent failures; create a troubleshooting section listing compile commands per OS.
  • Add request context timeout enforcement in controllers.go—currently no per-operation timeout; wrap image operations with context.WithTimeout to prevent resource exhaustion on very large uploads.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 6a274b4 — fix: Dockerfile build errors (#446) (jgunnink)
  • 1d4e251 — Fix: Removed deprecated argument from Readme.MD (#430) (easymoney322)
  • 8f36a26 — docs: remove obsolete build badge (h2non)
  • 6cd9edd — Update README.md (#351) (chrisedebo)
  • 6a40583 — Add URL unescaping for file query parameter. (#414) (TurbineJoshua)
  • 0d241c8 — Update middleware.go (#353) (alexbowers)
  • 7efb66c — Fix operation name typo (#417) (pedroetb)
  • b632dae — Fix typos (#405) (kianmeng)
  • 35c87ba — Decompression exploit check (#404) (SeaaaaaSharp)
  • cfbf8d7 — Return with and heigh of the generated images (#382) (CarlSchwan)

🔒Security observations

  • High · Outdated Go Version in Dockerfile — Dockerfile (ARG GOLANG_VERSION=1.17). The Dockerfile uses Go 1.17, which is significantly outdated (released August 2021). This version has multiple known security vulnerabilities and is no longer actively maintained. The current Go module specifies go 1.12, which is even older. Fix: Update to Go 1.21 or later. Update go.mod to reflect the minimum supported Go version. Review Go security advisories for 1.12-1.17 at https://go.dev/security
  • High · Outdated Third-Party Dependencies — go.mod. The go.mod file contains outdated dependencies with known vulnerabilities: github.com/rs/cors v0.0.0-20170727213201-7af7a1e09ba3 (2017) and github.com/h2non/bimg v1.1.7. These have not been updated in years and likely contain unpatched security issues. Fix: Run 'go list -u -m all' to identify outdated packages. Update all dependencies to their latest versions. Run 'go mod tidy' and test thoroughly. Consider using 'go mod why' to understand dependency chains.
  • High · URL Source Enabled Without Validation — docker-compose.yml (command section). The docker-compose.yml enables URL source functionality with '-enable-url-source' flag. This allows the service to fetch images from arbitrary URLs, creating potential attack vectors for SSRF (Server-Side Request Forgery) attacks, if URL validation and filtering is not properly implemented in the code. Fix: Implement strict URL validation: whitelist allowed domains, reject private IP ranges (127.0.0.1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16), validate URL schemes. Consider disabling URL source in untrusted environments or using a firewall to restrict outbound connections.
  • High · Missing Security Headers Configuration — middleware.go, server.go. No visible security headers (Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security) are configured in the middleware.go file structure. The application processes and returns images without apparent protection against content-type sniffing or clickjacking. Fix: Implement security headers middleware that adds: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Content-Security-Policy restrictions, Strict-Transport-Security (if using HTTPS), X-XSS-Protection headers.
  • Medium · Hardcoded Test Certificates in Repository — testdata/server.crt, testdata/server.key. Test SSL certificates (server.crt and server.key) are committed to the repository under testdata/. While these are test certs, storing any certificates or keys in version control is a bad practice that could be accidentally deployed to production. Fix: Keep test certificates out of the main repository. Use .gitignore to exclude them. Generate certificates locally for testing. If they must be versioned, use a separate non-production repository or document they are for testing only.
  • Medium · Missing Input Validation Documentation — params.go, source.go, source_http.go, source_fs.go. The params.go and source files suggest image processing parameters and URL/file sources are accepted. Without visible input sanitization in the file structure, there's risk of path traversal, injection attacks, or resource exhaustion through crafted inputs. Fix: Implement comprehensive input validation: validate image dimensions, file sizes, parameter ranges. Use allowlists for permitted operations. Implement rate limiting and request timeouts. Sanitize all file path inputs to prevent directory traversal.
  • Medium · Exposed Service Port Without Authentication — docker-compose.yml (ports: 8088:8088), README.md. The docker-compose.yml exposes port 8088 to all interfaces without any authentication mechanism visible in the configuration. The README mentions public HTTP service capability, suggesting the microservice may be exposed to untrusted networks. Fix: Implement authentication/authorization layer (API keys, OAuth2, mTLS). Use network policies to restrict access. Place the service behind a reverse proxy with authentication. Implement rate limiting and DDoS protection. Use HTTPS/T

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · h2non/imaginary — RepoPilot