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/stacksendpoints for listing, reading, creating, and modifying stacks, plus astack_idfilter on asset listings. - Backfilled burst detection across existing libraries.
Search
- 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_assetsandsearch_assets, including bounding boxes that cross the antimeridian. - Added an
album_idsearch filter and ascending order to asset listings. - Renamed the
search_assetscapture-time and album parameters tolocal_datetime_*andalbum_idto matchlist_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/randomand/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
withHiddenwas 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
dateTimeRelativein 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-uproute 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_assettool that returns a photo’s pixels to the model so it can read text in or analyze the image. - Added a
save_assettool 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_faceendpoint (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/albumsfor 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=variantstoken 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
variantstoken, 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 web and mobile apps, 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-updateendpoint. - Added a single-asset
PATCH /api/assets/{asset_id}endpoint. - Added image variant sizing improvements (a new
small=720rung and larger thumbnails) and ThumbHash placeholders for faster perceived loading. - Moved the
/api-keysrouter under the/apiprefix and tracked API key usage vialast_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_labelandplace_nameto 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}/reassignendpoint. - Implemented
GET /api/facesin 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_peopleas an MCP tool, and set up a demo account with sample data.
API & SDK
- Added an
include_unverifiedparameter 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_urlsAPI 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 web and mobile apps.
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/countsendpoint 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_assetslist 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_assetsMCP 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/immichendpoint. - 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_idparameter to the events endpoint for pagination.
Immich compatibility
- Deployed the Immich adapter to production.
- Added Immich sessions, checkpoints, and the
/sessionendpoints. - Added SHA-1 checksum support in both the Gumnut API and the Immich adapter.
- Added the ability to constrain queries by
device_idanddevice_asset_ids.
Sync & events
- Implemented an events endpoint for client sync.
Albums
- Added
startDateandendDatefields to album responses.