Skip to main content
This page lists notable user- and developer-facing changes to Gumnut, grouped by month and category. For a high-level overview, see Monthly progress.

Photo editing

  • Added a browser photo editor with crop presets, rotation, mirroring, pointer and keyboard crop controls, and pinch-to-resize on touch devices.
  • Saved edits as asset versions, reopened saved crop settings, and added confirmed revert-to-original and current-versus-original downloads.
  • Updated viewer images, timeline tiles, and album covers after an edit without requiring a page refresh.
  • Added unsaved-edit guards and recovery from save conflicts while keeping the working edit available.
  • Raised the editor’s pixel budget to 64 MP where the browser supports it, retained a 16 MP fallback, and limited output to the source image’s size.

Library management

  • Added library creation and switching in the web app and scoped browsing, uploads, and new Assistant conversations to the selected library.
  • Added Viewer and Collaborator roles and showed owned and joined libraries with their owner and the caller’s role.
  • Added an owner Share surface for invitation links, QR codes, expiration and join limits, member role changes, and member removal.
  • Added signed-in invitation previews, explicit joining, and a Leave library flow for members.
  • Charged member uploads and asset-version growth to the library owner’s storage allowance and recorded the contributor on new uploads.
  • Prevented deletion of a user’s last live library and cleared inaccessible library data when users lost membership.
  • Updated web controls when roles changed and explained permission failures without duplicate messages.

Browsing and filters

  • Added an always-open filter rail to Search, including media type, search entries in browser history, and explicit query submission.
  • Refreshed filtered search results after edits that affected their facets and stopped pagination using the server’s has_more signal.
  • Improved desktop timeline scrubbing and calendar destinations, preserving photo anchors through layout changes and viewer return.
  • Added grid-to-viewer opening and dismissal animations, smoother Info-panel transitions, and animated photo stacking.
  • Kept cached photo grids visible when returning from the viewer and preserved native browser edge-back gestures on phones.
  • Added day-of-month axis labels to date histograms covering a single month.

Web app navigation

  • Reworked navigation with per-page headers, a floating selection action bar, mobile bottom navigation, and responsive filter controls.
  • Added standalone home-screen launch with app icons and safe-area spacing for mobile controls.
  • Remembered Info-panel visibility across sessions and improved zoom sizing for smaller photos.
  • Added a Demo mode preference that presented aliases for person names across REST and MCP responses while preserving stored names.
  • Added recovery actions for route failures and clearer authentication, expired-session, and retry guidance.

Uploads and asset handling

  • Added folder uploads and skipped known non-media files in upload batches.
  • Queued additional upload batches instead of refusing them, with an Up next list and a removable queue that preserved each library and album target.
  • Extended upload timeouts, reduced refresh traffic during large batches, and reported file failures and album-association failures separately.
  • Accepted .hif HEIF uploads.
  • Raised display proxies to a maximum 6144-pixel edge, converted them to sRGB, and applied the same edge limit and sharper encoding to new video stills.
  • Added ThumbHash placeholders for video thumbnails.

Assistant and MCP

  • Published the Gumnut plugin in ChatGPT.
  • Added support for connecting Grok and Muse to your Gumnut photo library, alongside ChatGPT and Claude.
  • Improved compatibility with other MCP clients.
  • Supported modern sessionless MCP clients alongside legacy clients.

API and SDK

  • Added library membership and invitation APIs and restricted management, preview, joining, and leaving to first-party Gumnut sessions.
  • Added media_type filtering and has_more to asset search, and exposed the current rendering’s file_size_bytes on asset responses.
  • Added current-user preference updates, including immich_library_id.
  • Made matching named album, person, and library creates reuse existing resources, returning 200 for a match and 409 for conflicting supplied fields; rejected blank names and occupied-name renames.
  • Published TypeScript SDK 0.170.0–0.173.0 and Python SDK 0.164.0–0.167.0, including sharing methods, search filters, and user preferences.

Immich compatibility

  • Updated the adapter to Immich v3.2.0 and added the public login-configuration endpoints.
  • Added a Gumnut settings selector for Immich’s library, allowing owned or Collaborator libraries and resetting sync when the choice changed.
  • Kept default library selection to the oldest owned live library.
  • Honored the edited flag in batch archives and reported original sizes in download-info responses.
  • Aligned edit rotation angles with Immich and preserved created albums and successful initial memberships when a later association failed.

Faces and reliability

  • Bounded face-clustering memory for large libraries and batched periodic clustering eligibility checks.
  • Preserved face assignments and manual face edits made while clustering ran, and excluded empty people from centroid matching.
  • Retried transient image-delivery failures and verified signed asset URLs before serving cached content.

Documentation

  • Documented library sharing, folder uploads, named-create retry behavior, and choosing the library used by Immich.
  • Updated ChatGPT setup to use the Gumnut plugin and documented MCP bearer challenges and sessionless-client compatibility.
  • Refreshed Immich compatibility, including stacks, edited downloads, and the Live Photo limitation.

Browsing and filters

  • Added composable People, Date, Album, and Media type filters across Photos, album detail, and Map, making it possible to narrow a view to combinations such as two people in a particular year and location.
  • Added the Album facet to Photos, including album-name search and a Not in any album mode.
  • Added favorites with heart and keyboard shortcuts, tile badges, bulk favorite/unfavorite actions, and a favorite filter that can be combined with People, Date, Album, and Media type filters across Photos, album, and Map views.
  • Added the Date histogram to Photos and album detail with adaptive day, week, month, or year buckets, brushing, keyboard selection, and retryable states.
  • Propagated media-type filtering through Photos, album, and Map queries, including timeline counts and map results.
  • Added map filter-rail support, restored the map Date histogram over the geotagged population, and kept its counts stable during viewport-only changes.
  • Preserved each surface’s browsing order through counts, scrubbers, and viewer navigation: albums remain oldest-first while libraries and people remain newest-first.
  • Replaced the Albums Load more button with safe infinite scrolling, and paged People and featured-face pickers without consuming an unconfirmed restored cursor.
  • Improved search for filename stems and kept one oversized candidate from disabling reranking for the rest of a query.

Web app

  • Restored saved browsing data before background revalidation across the Photos timeline, Albums, People, Search, Trash, API keys, and Map, with successful web queries retained for seven days.
  • Kept usable saved results visible through refresh failures with a scoped Retry action, while distinguishing background refreshes from filter and map-camera transitions.
  • Consolidated Settings into one scrolling page behind a single bottom-anchored navigation entry, and moved Help & feedback into the navigation footer.
  • Replaced plain Loading text with the animated Gumnut mark across the app, used a layout-preserving skeleton for the initial photo grid, and respected reduced-motion preferences.
  • Made the People page denser on phones with three face columns and kept long names within their tiles.
  • Prevented the People filter picker from shifting when a selection is made, moved Clear into its header, auto-hid its scrollbar, and aligned the mobile sheet controls.

Uploads and asset handling

  • Added a file-picker upload button and empty-state upload action for touch-primary devices that cannot drag and drop.
  • Kept uploads, progress, and album association alive across in-app navigation, and reported partial or failed album associations accurately.
  • Added processing indicators in the asset Info panel for People, AI descriptions, location, and video details.
  • Added progress feedback while downloading multiple photos.
  • Added asset-version reads, including current-version fields and GET /api/assets/{asset_id}/versions.
  • Added append, replace, revert, and delete operations so clients can save edited renderings while preserving their relationship to the original upload and restore the original when needed.

API and SDK

  • Added media_type to list_assets and album membership filtering to geo clusters.
  • Added bbox and center plus radius filters to asset counts so count populations can match spatially filtered listings.
  • Published TypeScript SDK 0.150.0–0.169.0 and Python SDK 0.144.0–0.163.0, including typed asset-version and spatial count-filter support.
  • Removed deprecated singular person_id and search-threshold aliases from the public API contract, and rejected unknown query parameters on primary asset routes.

Immich compatibility

  • Completed the Immich REST stack surface with single-asset removal and bulk-dissolve operations, and moved stack sync from full-table snapshots to cursor-driven events.
  • Propagated stack membership through sync and upload-ready payloads, emitted stack-update events, and made transiently missing stack rows retry safely.
  • Added streamed Immich-compatible batch-download archives with strict preflight validation, safe filenames, and signed-URL redaction in logs.
  • Added Immich edit routes for reading, applying, and removing crop, rotate, and mirror edits, with server-side rendering and edit-ready events.
  • Made Immich surfaces report edited assets correctly, honor original versus edited downloads, and forward byte ranges for resumable downloads.
  • Suppressed stale face geometry while an edited rendering is current and restored it when the original rendering returns.
  • Added Immich favorite reads, writes, filters, map markers, and sync preferences.

Demos and documentation

  • Shipped the standalone sandboxed macOS upload client, which reviews local and network-folder changes before uploading photos and videos to a Gumnut library.
  • Documented exact-content duplicate detection and its per-library behavior, spatial filters on asset counts, current Python and TypeScript SDK usage, OAuth discovery, and the macOS uploader demo.

Map

  • Added a Map view to the web app: an interactive basemap with a heatmap of where your photos were taken, served from self-hosted map tiles.
  • Added hover popups summarizing a hotspot, with a click-through that drills into those photos in the grid.
  • Added date, people, and album filters to the map, and preserved the viewport when filters change.
  • Wired the map into the asset viewer so next and previous step through the photos currently in view.
  • Added a map preview to the asset info panel.
  • Started the map at your home timezone and fixed rendering of CJK place labels.

Bursts and stacking

  • Added burst detection, which groups a rapid sequence of shots into a single stack.
  • Collapsed bursts in the web timeline into one tile with a frame count, and added a burst chip and member strip in the viewer.
  • Added viewer burst corrections: set the cover frame, remove a frame from the burst, or unstack it.
  • Added manual stacking — select photos and stack them from the selection bar.
  • Added /api/stacks endpoints for listing, reading, creating, and modifying stacks, plus a stack_id filter on asset listings.
  • Backfilled burst detection across existing libraries.
  • Fused dense and sparse retrieval with reciprocal rank fusion, then reranked the top candidates with a cross-encoder.
  • Added full-text indexes over authoritative metadata so camera and place terms match reliably.
  • Separated metadata from image embeddings so visual similarity is no longer diluted by text.
  • Reduced search latency under concurrent load.
  • Derived capture time for screenshots from their filenames.

API and SDK

  • Added GET /api/assets/geo-clusters, which clusters assets by location for map display.
  • Added radius and bounding-box filters to list_assets and search_assets, including bounding boxes that cross the antimeridian.
  • Added an album_id search filter and ascending order to asset listings.
  • Renamed the search_assets capture-time and album parameters to local_datetime_* and album_id to match list_assets. The previous spellings were accepted during a transition and have since been removed.
  • Raised the bulk ID and request cap to 200.
  • Required an explicit scope when creating an API key, and allowed library-scoped keys to upload assets.
  • Added filtering and ordering to API key listings.

Apps

  • Added advanced search filters (people and date range) to the web app.
  • Added an in-app feedback form and a header help menu linking to the documentation.
  • Added long-press multi-select on photo tiles, pinch-to-zoom and panning in the viewer, and swipe-up to open the info panel on mobile.
  • Showed the AI-generated description alongside the editable caption in the info panel.
  • Improved the person detail page with an “Add a name” action and merge by name, and improved the empty People view.
  • Showed an album’s date range in its header.
  • Persisted the timeline cache and preloaded routes on intent for faster navigation.
  • Simplified the sign-up form to the required fields.
  • Began rolling out a native Gumnut Assistant chat in the web app behind a feature flag, with streaming replies and tool calls against your library.

MCP

  • Rendered capture dates in the MCP app in each photo’s wall-clock time rather than the viewer’s timezone.
  • Fixed connecting Claude to Gumnut over MCP when sign-in returned a redirect.

Immich compatibility

  • Retargeted the adapter to Immich v3.1.0, by way of v3.0.0 GA and v3.0.3.
  • Collapsed burst stacks in the Immich timeline and implemented the stack read, create, and set-cover endpoints.
  • Folded camera and place filters into the free-text search query.
  • Implemented /search/random and /search/explore.
  • Improved immich-go compatibility: accepted x-api-key, supported criterion-less metadata search, and fixed a 422 on jobs pause and resume.
  • Fixed expired-token detection so Immich clients re-login.
  • Fixed hidden people appearing when withHidden was omitted, a rating of 0 not mapping to unrated, and albums losing their initial assets at creation.
  • Filtered map markers to geotagged assets and applied dateTimeRelative in minutes, matching Immich.
  • Forwarded asset listing order to the Gumnut API and raised the scan page size.

Performance, reliability and security

  • Fixed cross-table deadlocks in the face pipeline and guaranteed retry for skipped face merges.
  • Moved image inference off the API event loop and batched background-task creation during upload.
  • Corrected malformed UTC-clock EXIF capture dates.
  • Enforced an inactive-user authentication kill switch and hardened API key verification.
  • Patched security advisories in Vite, Clerk, cryptography, Pillow, Starlette, and Click.

Documentation

  • Documented location-based browsing across the API, SDKs, MCP, and Immich, including the new search filters and bounding-box support.
  • Documented connecting any MCP client, including local models, to Gumnut.

Website

  • Launched a new public marketing site at gumnut.ai, with Home, Platform, Enterprise, About, and Contact pages.

Apps

  • Applied the Gumnut design system to the web app, including a new dark mode.
  • Added a new Gumnut-hosted /sign-up route alongside the branded sign-in page.
  • Added album management in the web app: create, rename, edit description, and delete.
  • Added people management in the web app: rename, merge, and set a featured face.
  • Added single- and multi-asset download.
  • Added a move-to-trash action, a delete-face action, and the ability to draw a box in the viewer to create a face.
  • Added “set as album cover” and “remove from album” viewer actions, and showed which albums an asset belongs to in the info panel.
  • Parallelized uploads with an ETA and an add-to-album step after upload.
  • Made the web app mobile-friendly: a nav drawer, smaller phone thumbnails, a responsive info panel, an icon-collapsing multi-select action bar, and touch-swipe navigation in the viewer.
  • Paginated asset counts so the timeline scrolls past 200 months.

Video

  • Added video playback to the web asset viewer, with the video filling the column like an image and Space toggling play/pause.
  • Rendered video thumbnails in the timeline, viewer, web grid tiles (with a duration badge and hover preview), and the MCP app grid.
  • Tone-mapped HDR (HLG/PQ) video thumbnails to SDR.
  • Extracted make, model, and date-time from Samsung video tags.
  • Fixed black-frame flashes, poster letterbox pop, and duration-badge clipping when paging to videos, and stopped a mouse swipe from starting playback.

MCP

  • Added a view_asset tool that returns a photo’s pixels to the model so it can read text in or analyze the image.
  • Added a save_asset tool for ingesting new photos and videos into a library.
  • Rendered video thumbnails in the MCP app grid, added swipe navigation, and matched the viewer chrome to the web app on small screens.
  • Fixed MCP tool calls being counted twice against rate limits.

Faces

  • Added a SCRFD face-detection backend and made it the default detector.
  • Added a create_face endpoint (and web UI) for manually drawing face boxes, and the ability to delete a face.
  • Exposed face confidence and source in the API.
  • Improved RetinaFace recall and backfilled previously missed faces.

Timezones

  • Added user home-timezone handling so photos without embedded timezone information get a sensible local time — inferred from device neighbors, a timezone hint sent by the app, or a home zone derived from a user’s other photos.
  • Cleared false UTC offsets from captures that lack offset information.

Immich compatibility

  • Passed ThumbHash placeholders through to Immich clients.
  • Exposed real storage quota to Immich and remapped over-quota responses from 507 to 400.
  • Implemented POST /api/faces (manual face creation) in the adapter.
  • Fixed a 500 on GET /api/albums for albums with naive start/end dates.
  • Isolated the refreshed JWT per request as a safeguard against a theoretical cross-user leak.

API & SDK

  • Added an include=variants token so asset reads return only the requested image variants, keeping default responses lean.
  • Added single-asset streaming download via a Content-Disposition attachment.
  • Published TypeScript SDK 0.108.0–0.125.0 and Python SDK 0.103.0–0.119.1 tracking these API changes.

Documentation

  • Documented manual face boxes, lean asset responses and the variants token, MCP tool-call rate limits, asset capture-time handling, and original-asset download behavior.
  • Pointed Immich setup docs at immich.gumnut.ai and refreshed the docs brand mark and favicon.

Apps

  • Launched the new Gumnut web app at app.gumnut.ai, a Vite + React single-page app that replaces the previous web client.
  • Added a virtualized photo timeline with justified rows, per-month data loading, date grouping, and a jump scrubber on both web and mobile.
  • Added an asset viewer with EXIF metadata and prev/next navigation scoped to albums and people.
  • Added albums, people, search, uploads (with per-image upload progress thumbnails), and API key management.
  • Extended the virtualized timeline to the album and person views and migrated search to a justified, virtualized grid — all with infinite scroll, replacing the previous “Load more” buttons.
  • Added a dedicated sign-in page for signed-out visitors, an Immich settings page linking to the Immich mobile app, and an MCP setup page on the Chat tab for connecting Gumnut to Claude or ChatGPT.
  • Retired the legacy Next.js web client, completing the move to the new app.
  • Fixed the home page loading slowly on large libraries by paginating the timeline instead of fetching the entire asset list.
  • Fixed asset search on Android.

Video

  • Added basic video support: thumbnail generation, width/height and duration extraction at ingest, and a database schema for video metadata.
  • Added streaming video playback through the CDN, including HTTP range request support for seeking.
  • Surfaced video thumbnails and duration through the Immich adapter, and backfilled thumbnails, dimensions, and duration for existing videos.

Faces

  • Switched face clustering to a graph-based approach (HNSW + Chinese Whispers).
  • Added crowd-face filtering to keep large background crowds from polluting clusters.
  • Shipped a self-service face cleanup dashboard for reviewing and triaging clusters, including an unassigned-faces tab.
  • Began migrating face embeddings from FaceNet512 to ArcFace, with dual-write ingestion and new embedding/centroid storage.

Immich compatibility

  • Added map markers and enabled the map feature flag.
  • Added a read-only “On this day” memories endpoint.
  • Added user edits to asset metadata (description, date/time and timezone, and GPS), wired through to single- and bulk-asset edit endpoints.
  • Added Immich-compatible trash (soft-delete) with retention, honored across REST, sync stream, timeline, statistics, and WebSocket events.
  • Served a sharper thumbnail size (small/720) for wide and panoramic photos in Immich clients.

Library management

  • Added library trash/restore with an async purge window and SDK support.

API & SDK

  • Added a POST /api/assets/bulk-update endpoint.
  • Added a single-asset PATCH /api/assets/{asset_id} endpoint.
  • Added image variant sizing improvements (a new small=720 rung and larger thumbnails) and ThumbHash placeholders for faster perceived loading.
  • Moved the /api-keys router under the /api prefix and tracked API key usage via last_used_at.
  • Fixed semantic search returning the same asset multiple times by de-duplicating stored embeddings, adding a uniqueness constraint, and making embedding writes idempotent.

Location

  • Added reverse geocoding: selected a provider and added a backfill task that populates human-readable place names and location metadata.
  • Added display_label and place_name to the asset metadata response.
  • Introduced layered asset metadata (file, reverse-geo, and user layers) with rename cascade support.

Faces

  • Added density-aware gates that reject loose clusters at creation and during per-asset assignment.
  • Added density-aware auto-merge and auto-dissolve of unnamed people on reuse.
  • Added clustering debounce and re-clustering of unnamed people, plus face quality filtering.

Immich compatibility

  • Added a People merge endpoint and a PUT /api/people/{id}/reassign endpoint.
  • Implemented GET /api/faces in the Immich adapter.
  • Added the trash (soft-delete) backend, schema, and filtering.
  • Updated for compatibility with Immich 2.6.x and 2.7.5, and made the server features endpoint return accurate feature flags.
  • Added an Immich compatibility documentation section.

CDN

  • Completed the CDN migration end-to-end, including Immich adapter asset fetching and migration cleanup.

Image descriptions

  • Added a backfill mechanism to generate descriptions for existing assets.
  • Added Google Gemini video descriptions, alongside the image description providers.

MCP & ChatGPT app

  • Improved MCP app single-entity and zoom views, added a “Load more” button to album and person detail views, and adjusted thumbnail sizing.
  • Audited and rewrote MCP tool descriptions for LLM consumption and added MCP tool annotations (readOnlyHint, destructiveHint, and others).
  • Began the ChatGPT app submission: published the privacy policy, exposed merge_people as an MCP tool, and set up a demo account with sample data.

API & SDK

  • Added an include_unverified parameter to the list people endpoint.
  • Added pagination parameters and response fields to album asset endpoints.

Documentation

  • Documented the authentication architecture.

Image descriptions

  • Added AI-generated descriptions for uploaded assets, with a provider-agnostic inference service and OpenRouter (Qwen) integration.
  • Added the asset description data model and API response, and triggered description generation on upload.

CDN

  • Rolled out Cloudflare-based CDN asset delivery: photos-api infrastructure with additive asset_urls API changes, and migrated the web app, MCP app, and SDKs to consume them.

MCP app

  • Added dark/light theme support and configurable CSP via a FastMCP 3.x upgrade.
  • Fixed iframe sizing, duplicated headings, and hardened error handling and sizing edge cases.

Faces

  • Tightened the face assignment threshold, added post-clustering merge detection, improved centroid calculation, and added face quality filtering for clustering.

Search & people

  • Added the ability to search and filter people by name.
  • Added an endpoint to merge people.

Immich compatibility

  • Updated to Immich v2.5.0 and added WebP image support.
  • Made OAuth the default login method for the Immich mobile app.

Performance & reliability

  • Cut photos-api deploy time from ~30 minutes to ~5 minutes.
  • Added per-user rate limiting with weighted costs and granular limits for MCP tool endpoints.
  • Streamed uploads (single-pass checksum and S3 upload) and added a maximum upload file size.
  • Added an /api/assets/counts endpoint and date-range filtering to speed up timeline thumbnail loading.

Documentation

  • Restructured the public documentation site and refreshed architecture docs.

Albums

  • Added album cover images (album_cover_url) and album thumbnails.

API

  • Added batch ID filtering (ids) to list endpoints for bulk viewing.
  • Added album_assets list and get endpoints with ID filtering.
  • Added date-range filtering to the assets list endpoint.
  • Returned full URLs directly in API responses instead of requiring client-side construction.

MCP

  • Completed the next-generation MCP rollout: client migration, legacy MCP deprecation, and Playwright tests for the MCP app.
  • Enabled stateless MCP HTTP mode for multi-instance scaling.

Sync & events

  • Designed and implemented first-class modeling of events and replaced the v1 events API with a v2 implementation.

Faces

  • Sped up face detection by downscaling images before detection and running detection and embedding as a local task.

Performance, reliability & security

  • Added composite-key cursor pagination to prevent duplicate or skipped rows.
  • Scoped cursor subqueries by library to prevent cross-library information leaks.
  • Added a ping endpoint for uptime monitoring.
  • Fixed scroll position reset when navigating back from the photo detail view in the web app.

MCP

  • Shipped the next-generation Gumnut Photos MCP: the MCP foundation (Phase 1), the full Tier 1 toolset (Phase 2), and complete MCP authentication.
  • Added MCP tool enhancements: outputSchema, structuredContent, and tool titles.
  • Fixed dynamic client registration and the search_assets MCP tool.

HEIC support

  • Fixed HEIC metadata extraction (OffsetTime / SubsecTime read from the wrong EXIF IFD).
  • Fixed ML services failing to process HEIC images.
  • Pre-generated full-size WebP for HEIC files so they display in the browser, and served WebP instead of original HEIC for full-size thumbnails.

Immich compatibility

  • Implemented the .well-known/immich endpoint.
  • Added WebSocket infrastructure with authentication and Phase 1 events (upload, delete, session).
  • Added sync streaming with cursor-based pagination.
  • Formatted error responses in the Immich-compatible format.
  • Updated to Immich v2.4.1.

Sync & events

  • Added a starting_after_id parameter to the events endpoint for pagination.

Immich compatibility

  • Deployed the Immich adapter to production.
  • Added Immich sessions, checkpoints, and the /session endpoints.
  • Added SHA-1 checksum support in both the Gumnut API and the Immich adapter.
  • Added the ability to constrain queries by device_id and device_asset_ids.

Sync & events

  • Implemented an events endpoint for client sync.

Albums

  • Added startDate and endDate fields to album responses.