Skip to main content
Glama

imogen ist eine selbst gehostete Foto- und Videobibliothek für ein Home Lab. Es verwahrt deine Fotos auf Hardware, die du kontrollierst, und öffnet sie für alles, was du bauen möchtest: eine Weboberfläche, eine REST-API, ein TypeScript-SDK für eine Mobile-App und einen MCP-Endpunkt, damit deine KI-Assistenten die Bibliothek ebenfalls durchsuchen können.

  • Justierte Zeitleiste — Fotos behalten die Proportionen, in denen sie aufgenommen wurden, gruppiert nach Tagen

  • Alles, was eine Kamera produziert — HEIC, RAW, JPEG, Video, Live Photos

  • Installierbar — die Weboberfläche ist eine PWA und funktioniert offline

  • Zwei Anmeldewege — lokale Konten oder Single Sign-on über Authentik, Keycloak, Google oder alles andere, das OIDC spricht

  • Gebaut, um darauf zu bauen — OpenAPI, ein SDK und ein OAuth-2.1-Server, sodass eine Drittanbieter-App ein vollwertiger Bürger und kein Anhängsel ist

  • Personen — optionale Gesichtsgruppierung, die vollständig auf deinem eigenen Server läuft

  • Ein Tresor — Fotos, die zum Ansehen eine Passphrase benötigen, verborgen vor allem anderen

  • Teilen — veröffentliche ein Album oder ein einzelnes Foto als Link, mit optionalem Passwort, Ablaufdatum und wahlweise ein- oder ausgeschalteten Downloads

  • Administration — Personen einladen, Konten sperren, die Verarbeitungswarteschlange beobachten, Apps trennen und sehen, was gerade öffentlich ist

  • Bereit für Agenten — verbinde Claude oder Grok per URL mit deiner Bibliothek


Betrieb

curl -O https://raw.githubusercontent.com/ergofobe/imogen-server/main/docker-compose.yml
docker compose up -d

Öffne http://localhost:3000. Das erste Konto, das du erstellst, wird zum Administrator.

Das ist die gesamte Installation. imogen benötigt Postgres, und die Compose-Datei startet eine Instanz; es gibt keinen Message-Broker, keinen Cache und keinen Sidecar.

Konfiguration

Alles ist eine Umgebungsvariable, die beim Start validiert wird — der Server weigert sich, bei einer fehlerhaften Konfiguration zu booten, anstatt später unter Last auszufallen.

Variable

Default

Funktion

IMOGEN_PUBLIC_URL

http://localhost:3000

Die URL, unter der Menschen imogen erreichen. OAuth- und Share-Links werden daraus erstellt, daher muss sie hinter einem Reverse-Proxy korrekt sein.

DATABASE_URL

Postgres-Verbindungsstring. Erforderlich.

IMOGEN_DATA_DIR

/data

Wo die Fotos liegen. Sichere diesen Ordner.

IMOGEN_SECRET

generiert

Signiert Sitzungen. Wird beim ersten Start generiert und gespeichert, falls nicht gesetzt.

IMOGEN_ALLOW_SIGNUP

true

Ob irgendwer ein Konto erstellen darf. Das erste Konto ist immer erlaubt. Nur ein Startwert — ein Administrator kann dies in der App ändern, und dessen Einstellung gewinnt.

IMOGEN_TRASH_RETENTION_DAYS

30

Wie lange gelöschte Fotos wiederherstellbar sind. Ebenfalls ein Startwert, den ein Administrator ändern kann.

IMOGEN_JOB_CONCURRENCY

4

Fotos, die gleichzeitig verarbeitet werden. Erhöhe den Wert auf einer Maschine mit freien Kernen.

Verwaltung

Das erste erstellte Konto wird zum Administrator. Auf seiner Einstellungsseite gibt es einen Link zu /admin; dort werden Konten, Einladungen, die Verarbeitungswarteschlange, verbundene Anwendungen, Speicher und Share-Links verwaltet.

Der Bereich ist nicht einfach für alle anderen gesperrt — er antwortet mit einem schlichten 404, identisch zu dem, den der Server für einen Pfad liefert, von dem er noch nie gehört hat. Man kann ihn also nicht finden, indem man danach sucht. Alles, was nach einem Administrationspanel sucht, erfährt nichts.

Um jemanden zu einem geschlossenen Server hinzuzufügen, erstelle eine Einladung und sende den Link. Der Link wird nur einmal angezeigt und nur als Hash gespeichert. Wenn er verloren geht, widerrufe ihn und erstelle einen neuen.

Single Sign-on

Richte imogen auf einen beliebigen OIDC-Anbieter aus. Setze die Redirect-URI in deinem Anbieter auf https://photos.example.com/api/v1/auth/oidc/callback.

IMOGEN_OIDC_ISSUER: https://auth.example.com/application/o/imogen/
IMOGEN_OIDC_CLIENT_ID: ...
IMOGEN_OIDC_CLIENT_SECRET: ...
IMOGEN_OIDC_LABEL: Sign in with Authentik
IMOGEN_OIDC_ADMIN_VALUE: imogen-admins   # members of this group become administrators
IMOGEN_OIDC_ACCOUNT_URL: ''              # optional; guessed for Authentik and Keycloak

Bestehende lokale Konten werden anhand der bestätigten E-Mail-Adresse verknüpft. Das Aktivieren von SSO lässt also niemanden außen vor.

Der Anbieter besitzt Name und E-Mail der Konten, die er verwaltet: imogen liest sie bei jeder Anmeldung neu ein, zeigt sie in den Einstellungen schreibgeschützt an und verlinkt auf die eigene Kontoseite des Anbieters. Setze IMOGEN_OIDC_ACCOUNT_URL, wenn dieser Link nicht auf die automatisch angenommene Adresse zeigen soll.

Der Administratorstatus folgt IMOGEN_OIDC_ADMIN_VALUE, wenn du sie setzt — einschließlich des Entfernens, wenn jemand die Gruppe verlässt. Lass sie ungesetzt, und imogen fasst Rollen nie an; ein lokal beförderter Administrator bleibt einer.

Hinter einem Reverse-Proxy

imogen liefert einfaches HTTP aus und erwartet, hinter etwas zu sitzen, das TLS beendet. Leite X-Forwarded-For durch, damit Sitzungen eine sinnvolle Adresse aufzeichnen, erlaube große Request-Bodies für Video-Uploads und setze IMOGEN_PUBLIC_URL auf die externe URL.

photos.example.com {
    reverse_proxy localhost:3000
    request_body { max_size 8GB }
}

Related MCP server: immich-mcp

Personen

imogen kann Gesichter finden und die Fotos gruppieren, auf denen eine Person vorkommt. So kannst du jemanden einmal benennen und dann alles durchsuchen, worauf sie zu sehen ist. Erkennung und Identifizierung laufen auf deinem Server; kein Foto wird irgendwohin gesendet.

Sie ist aus, bis du sie einschaltest — auf der Personen-Seite. Beim Aktivieren werden etwa 190 MB an Erkennungsmodellen heruntergeladen und deine vorhandene Bibliothek im Hintergrund gescannt.

  • Fotos in deinem Tresor werden nie gescannt, und wenn du ein Foto in den Tresor legst, werden die darin bereits gefundenen Gesichter vergessen.

  • Niemand wird benannt, bis du ihn benennst. Unbenannte Gruppen werden angezeigt, damit du sie benennen kannst; beide können ausgeblendet werden.

  • Die Gruppierung tendiert eher dazu, eine Person auf zwei Gruppen zu verteilen, als zwei Personen zu einer zusammenzuführen. Wähle mehrere aus und sage ihr, dass es dieselbe Person ist.

Eine Anmerkung zu den Modellen. imogen verwendet die Modelle SCRFD und ArcFace von InsightFace, die für die nicht-kommerzielle Forschung lizenziert sind. imogen bringt keine Modelle mit: Dein Server lädt sie herunter, wenn du die Funktion aktivierst. Die Lizenzentscheidung bleibt also bei dir. Wenn das nicht zu deiner Situation passt, lass die Funktion aus.


Der Tresor

Manche Fotos sollten nicht nur einen unachtsamen Scroll entfernt sein. Verschiebe sie in den Tresor, und sie verschwinden vollständig aus der Bibliothek: nicht in der Zeitleiste, nicht in der Suche, nicht in deinen Alben, nicht in einem geteilten Link und nicht in irgendetwas, das ein KI-Assistent sehen kann.

Zum Öffnen braucht es eine Passphrase, die du erneut eingibst, obwohl du bereits angemeldet bist.

Ein paar Entscheidungen, die du kennen solltest:

  • Die Passphrase ist nicht dein Kontopasswort. Single-Sign-on-Konten haben kein lokales Passwort, und vor allem: Eine bereits angemeldete Sitzung sollte nicht ausreichen — ein offenes Laptop sollte nicht auch noch diesen Tresor öffnen.

  • Nur eine Browser-Sitzung kann ihn öffnen. Ein API-Token oder ein MCP-Connector kann durchaus gültige Anmeldedaten besitzen und trotzdem keinen Zugang haben. Das ist konstruktionsbedingt, kein Versehen.

  • Er schließt sich von selbst nach fünfzehn Minuten, oder sofort, wenn du ihn darum bittest.

  • Niemand kann ihn für dich zurücksetzen. Es gibt keinen Wiederherstellungspfad — genau das ist der Sinn.

Das Verschieben eines Fotos in den Tresor entfernt es auch aus jedem Album, denn ein Album lässt sich teilen.


Einen KI-Assistenten verbinden

imogen spricht MCP, sodass ein Assistent deine Bibliothek durchsuchen, ein Foto ansehen und Alben verwalten kann — mit deiner Erlaubnis und sonst nichts.

Claude.ai oder Grok: Füge einen Connector hinzu, der auf https://photos.example.com/mcp zeigt. Es wird nichts von Hand eingefügt: Der Client findet imogen, registriert sich selbst und leitet dich zu einem Zustimmungsbildschirm weiter, der genau benennt, worum er bittet. Du kannst die Verbindung jederzeit in den Einstellungen widerrufen.

Ein lokaler Agent (Claude Code oder alles, was MCP über stdio spricht):

bun add -g @imogen/mcp
imogen-mcp login --server https://photos.example.com
{ "mcpServers": { "imogen": { "command": "imogen-mcp" } } }

Was ein Assistent tun kann

Tool

Berechtigung

search_photos · get_photo · get_photo_image · get_library_stats

library:read

list_albums · get_album

albums:read

create_album · add_to_album

albums:write

search_by_person · list_people

library:read

Jedes Tool ist auf das verbundene Konto beschränkt. Es gibt kein Tool, das etwas löscht, und nichts im Tresor ist für eines davon sichtbar. Nur Personen, die du benannt hast, sind auffindbar — unbenannte Gruppierungen und ausgeblendete Personen nicht.


Darauf aufbauen

Die API ist unter /api/v1/docs dokumentiert, mit der OpenAPI-3.1-Beschreibung unter /api/v1/openapi.json.

Es gibt Clients für fünf Sprachen in imogen-sdk — TypeScript, Rust, Python, Swift und Kotlin. In TypeScript:

bun add @imogen/sdk
import { ImogenClient } from '@imogen/sdk'

const imogen = new ImogenClient({ baseUrl: 'https://photos.example.com', token })

const page = await imogen.assets.list({ q: 'harbour', limit: 50 })
for await (const asset of imogen.assets.iterate()) console.log(asset.originalFilename)

// Picks its protocol by size: one request for photos, a resumable session for video.
await imogen.assets.uploadMany(files, {
  onFileComplete: (outcome, done, total) => console.log(`${done}/${total}`),
})

Eine Mobile-App schreiben

Jedes SDK bringt den OAuth-Client mit, den eine native App braucht — die Swift- und Kotlin-SDKs sind genau dafür da. Nichts ist fest verdrahtet: Die App registriert sich selbst und funktioniert daher mit jedem imogen-Server, auf den ihr Nutzer sie richtet.

import { OAuthClient } from '@imogen/sdk'

const oauth = new OAuthClient('https://photos.example.com')
const client = await oauth.register('My Photo App', ['myapp://oauth'])
const pending = await oauth.beginAuthorization(client.client_id, 'myapp://oauth')

// Open pending.authorizationUrl in the system browser, then on the callback:
const tokens = await oauth.completeAuthorization(pending, callbackUrl)

Uploads sind inhaltlich idempotent: Wenn ein Foto erneut gesendet wird, das der Server bereits hat, wird das vorhandene Asset zurückgegeben, statt eine zweite Kopie zu speichern. So kann eine Sync-Schleife einfach und trotzdem korrekt sein. Übergib deviceAssetId, und ein Client weiß, was er bereits gesendet hat, ohne ein eigenes Protokoll führen zu müssen.

Koppeln statt nach einem Hostnamen zu fragen

Der obige Ablauf setzt weiterhin voraus, dass die App weiß, mit welchem Server sie sprechen soll, und eine selbst gehostete Bibliothek liegt unter der Adresse, die ihr Besitzer gewählt hat. Das auf einer Telefontastatur zu tippen ist der schlimmste Moment bei der Installation einer solchen App — deshalb übernimmt der Browser das.

Einstellungen → GeräteGerät koppeln erstellt ein Einmal-Ticket und rendert es als QR-Code, der sowohl die Server-URL als auch den Code enthält. Die App liest das Quadrat und erledigt den Rest:

val invitation = parsePairingUri(scanned) ?: return
val oauth = OAuthClient(invitation.serverUrl)
val paired = oauth.pair(invitation.code, "imogen for Android", "imogen://oauth", Build.MODEL)

Was vor die Kamera kommt, ist ein Ticket, kein Token. Es ist nur einmal verwendbar, lebt fünf Minuten und bringt genau einen Autorisierungscode — gebunden an eine PKCE-Challenge, die das Gerät nie verlassen hat. Ein Foto von jemandes Bildschirm reicht also nicht. Der daraus resultierende Grant ist ein gewöhnlicher und erscheint wie jeder andere unter den verbundenen Anwendungen.

Dieselbe Seite bietet das Ticket auch als Link an, für ein Telefon, das bereits die Weboberfläche anzeigt: Ein Tippen darauf öffnet die App direkt.


Entwickeln

git clone https://github.com/ergofobe/imogen-server
cd imogen-server
bun install

docker compose -f docker/compose.dev.yml up -d     # Postgres
export DATABASE_URL='postgres://imogen:imogen@localhost:5432/imogen'
bun run db:migrate

bun run dev        # API on :3000
bun run dev:web    # web on :5173, proxying to the API
bun test          # needs the dev Postgres running
bun run typecheck
bun run lint

Tests laufen gegen eine echte Postgres-Instanz und einen echten HTTP-Server statt gegen Mocks. Genau die Teile, die es richtig zu treffen gilt — die OAuth-Abläufe, die Cursor-Paginierung, die Medien-Pipeline — sind genau die Teile, bei denen ein Mock dich im Stich ließe.

Aufbau

Package

Was es ist

packages/server

Hono-App: Routen, Auth, Medien-Pipeline, Job-Worker.

packages/web

Die React-PWA. Sie nutzt @imogen/sdk wie jeder Drittanbieter-Client, was das SDK ehrlich hält.

packages/mcp

Die stdio-Brücke für lokale Agenten.

Die Client-Bibliotheken liegen in einem eigenen Repository, imogen-sdk — TypeScript, Rust, Python, Swift und Kotlin, getestet gegen einen gemeinsamen Satz von Vertrags-Fixtures. @imogen/shared, die Zod-Schemas, gegen die dieser Server validiert und aus denen er sein OpenAPI-Dokument erzeugt, liegt ebenfalls dort: Es ist der API-Vertrag, und der Vertrag ist Sache der Clients, die sich daran halten müssen.

packages/server/src/api/sdk-contract.test.ts ist die eine Seite dieser Vereinbarung. Dieser Test startet eine echte App und steuert sie über den veröffentlichten TypeScript-Client – der einzige Ort, an dem die beiden Hälften nachweislich übereinstimmen.

Das Designdokument liegt unter docs/superpowers/specs.


Noch nicht umgesetzt

Semantische Suche — das Finden eines Fotos, indem man es beschreibt — ist nicht implementiert. Das Schema reserviert eine Vektorspalte für Assets und der Suchindex ist vorhanden, sodass sie ohne Migration nachgerüstet werden kann; heute deckt die Suche jedoch Dateinamen, Beschreibungen, Orte, Kamerametadaten und die von dir benannten Personen ab.

Ebenfalls nicht vorhanden: Reverse Geocoding (Koordinaten werden als Koordinaten angezeigt), Video-Transkodierung und S3-Speicher. Der Speichertreiber ist als Schnittstelle definiert, sodass S3 eine überschaubare Änderung ist, wenn man es möchte.

Die Gesichtsgruppierung funktioniert, hat aber ein paar Ecken und Kanten, die man kennen sollte. Sie erkennt frontale, einigermaßen gut beleuchtete Gesichter zuverlässig; Profilansichten, Sonnenbrillen, Bewegungsunschärfe und kleine Kinder – deren Gesichter sich schneller verändern, als ein gespeicherter Durchschnittswert mithalten kann – sind die Fälle, in denen sie dich enttäuscht. Sie tendiert eher dazu, eine Person auf zwei Gruppen aufzuteilen, als zwei Personen zusammenzuführen, mit der Begründung, dass Ersteres mit einem Klick zu beheben ist und Letzteres die Fotos von jemandem unter dem Namen einer anderen Person ablegt.

Lizenz

AGPL-3.0-or-later. Wenn du einen modifizierten imogen als Dienst betreibst, teile die Modifikationen.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ergofobe/imogen-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server