Skip to main content
Glama

imogen — это самостоятельно размещаемая библиотека фотографий и видео для домашнего сервера. Она хранит ваши фотографии на оборудовании, которым вы управляете, и открывает их для всего, что вы захотите построить: веб-интерфейса, REST API, TypeScript SDK для мобильного приложения и MCP-эндпоинта, чтобы ваши ИИ-ассистенты тоже могли искать в библиотеке.

  • Выровненная лента — фотографии сохраняют пропорции съёмки и сгруппированы по дням

  • Всё, что выдаёт камера — HEIC, RAW, JPEG, видео, Live Photos

  • Устанавливается — веб-интерфейс является PWA и работает офлайн

  • Два способа войти — локальные учётные записи или единый вход через Authentik, Keycloak, Google или любую другую систему, поддерживающую OIDC

  • Основа для разработки — OpenAPI, SDK и OAuth 2.1-сервер, так что стороннее приложение — полноценный участник, а не второстепенная надстройка

  • Люди — опциональная группировка лиц, полностью работающая на вашем сервере

  • Хранилище — фотографии, для просмотра которых нужна кодовая фраза и которые скрыты от всего остального

  • Общий доступ — публикация альбома или отдельной фотографии по ссылке, с необязательным паролем, сроком действия и включением или отключением скачивания

  • Администрирование — приглашайте людей, приостанавливайте учётные записи, следите за очередью обработки, отключайте приложения и видите всё, что сейчас публично

  • Готовность к ИИ-агентам — подключите Claude или Grok к своей библиотеке по URL


Запуск

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

Откройте http://localhost:3000. Первая созданная вами учётная запись становится администратором.

На этом установка заканчивается. imogen требует Postgres, и compose-файл поднимает его; не нужны ни брокер сообщений, ни кэш, ни дополнительный сервис.

Конфигурация

Всё настраивается переменными окружения, проверяемыми при запуске: сервер отказывается стартовать при неверной конфигурации, а не падает позже под нагрузкой.

Переменная

По умолчанию

Что делает

IMOGEN_PUBLIC_URL

http://localhost:3000

URL, по которому пользователи обращаются к imogen. На его основе формируются OAuth-ссылки и ссылки для общего доступа, поэтому за обратным прокси он должен быть указан верно.

DATABASE_URL

Строка подключения к Postgres. Обязательна.

IMOGEN_DATA_DIR

/data

Директория, где хранятся фотографии. Делайте резервные копии.

IMOGEN_SECRET

генерируется

Подписывает сессии. Если не задан, генерируется и сохраняется при первом запуске.

IMOGEN_ALLOW_SIGNUP

true

Разрешает ли кто угодно создавать учётную запись. Первая учётная запись допускается всегда. Это лишь начальное значение — администратор может изменить его в приложении, и его настройка имеет приоритет.

IMOGEN_TRASH_RETENTION_DAYS

30

Как долго удалённые фотографии можно восстановить. Также начальное значение, которое администратор может изменить.

IMOGEN_JOB_CONCURRENCY

4

Сколько фотографий обрабатывается одновременно. Увеличьте на машине со свободными ядрами.

Администрирование

Первая созданная учётная запись становится администратором. На её странице «Настройки» есть ссылка на /admin, где управляются учётные записи, приглашения, очередь обработки, подключённые приложения, хранилище и ссылки для общего доступа.

Раздел не просто закрыт для остальных — он отвечает обычной 404, точно такой же, как для несуществующего пути, так что его невозможно найти, даже если специально искать. Всё, что сканирует в поисках панели администрирования, не получает никакой информации.

Чтобы добавить кого-то на закрытый сервер, создайте приглашение и отправьте человеку ссылку. Ссылка показывается один раз и хранится только в виде хэша; если она потеряна, отзовите её и создайте новую.

Единый вход

Подключите imogen к любому OIDC-провайдеру. Укажите у провайдера redirect URI: 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

Существующие локальные учётные записи связываются по подтверждённому адресу электронной почты, поэтому включение SSO никого не оставит без доступа.

Провайдер владеет именем и адресом электронной почты учётных записей, которыми управляет: imogen перечитывает их при каждом входе, показывает в настройках в режиме только для чтения и даёт ссылку на страницу учётной записи у провайдера. Задайте IMOGEN_OIDC_ACCOUNT_URL, если эта ссылка должна вести не туда, куда предполагает imogen.

Когда переменная IMOGEN_OIDC_ADMIN_VALUE задана, статус администратора определяется её значением — в том числе снимается, когда человек покидает группу. Если оставить её незаданной, imogen не вмешивается в роли, и администратор, назначенный локально, остаётся администратором.

За обратным прокси

imogen отдаёт обычный HTTP и предполагает, что за ним находится прокси, завершающий TLS. Передавайте X-Forwarded-For, чтобы сессии записывали корректный адрес, разрешите большие тела запросов для загрузки видео и задайте IMOGEN_PUBLIC_URL равным внешнему URL.

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

Related MCP server: immich-mcp

Люди

imogen умеет находить лица и группировать фотографии, на которых есть каждый человек, так что вы можете один раз назвать человека и затем просматривать все снимки с ним. Детекция и распознавание выполняются на вашем сервере; ни одна фотография никуда не отправляется.

Функция выключена, пока вы её не включите, на странице «Люди». При включении загружается около 190 МБ моделей распознавания и в фоновом режиме сканируется существующая библиотека.

  • Фотографии в хранилище не сканируются никогда, а при переносе фотографии в хранилище уже найденные на ней лица забываются.

  • Никто не получает имени, пока вы его не дадите. Безымянные группы показываются, чтобы вы могли дать им имена, и те и другие можно скрыть.

  • Группировка скорее разделит одного человека на две группы, чем объединит двух людей в одну. Выделите несколько групп и укажите, что это один и тот же человек.

Примечание о моделях. imogen использует SCRFD и ArcFace из InsightFace, которые лицензированы для некоммерческих исследовательских целей. imogen не поставляет модели: ваш сервер загружает их при включении функции, поэтому решение о лицензии остаётся за вами. Если это не подходит вашей ситуации, оставьте функцию выключенной.

Хранилище

Некоторые фотографии не должны быть в одном неосторожном скролле от посторонних глаз. Перенесите их в хранилище, и они полностью исчезнут из библиотеки: их не будет ни в ленте, ни в поиске, ни в ваших альбомах, ни в опубликованной ссылке, ни в том, что может увидеть ИИ-ассистент.

Чтобы открыть хранилище, нужна кодовая фраза, которую нужно ввести снова, даже если вы уже вошли в систему.

Несколько решений, о которых стоит знать:

  • Кодовая фраза — это не пароль вашей учётной записи. Учётные записи единого входа не имеют локального пароля, и, что важнее, уже выполненного входа недостаточно: если ваш ноутбук открыт, это не должно открывать и хранилище.

  • Открыть его может только браузерная сессия. API-токен или MCP-коннектор могут обладать совершенно действительными учётными данными, но у них нет способа попасть внутрь. Это сделано намеренно, а не по недосмотру.

  • Оно закрывается само через пятнадцать минут или немедленно, когда вы попросите.

  • Никто не сможет сбросить его за вас. Пути восстановления не существует — в этом и суть.

Перемещение фотографии в хранилище также удаляет её из всех альбомов, ведь альбомом можно поделиться.

Подключение ИИ-ассистента

imogen говорит на MCP, поэтому ассистент может искать по вашей библиотеке, просматривать фотографии и управлять альбомами — с вашего разрешения и не более того.

Claude.ai или Grok: добавьте коннектор, указывающий на https://photos.example.com/mcp. Ничего не нужно вводить вручную: клиент сам обнаруживает imogen, регистрируется и отправляет вас на экран согласия, где точно указано, на что именно он запрашивает разрешение. Отозвать его можно в любой момент в настройках.

Локальный агент (Claude Code или любое другое решение, работающее с MCP через stdio):

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

Что умеет ассистент

Инструмент

Разрешение

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

Каждый инструмент ограничен рамками подключённой учётной записи. Нет ни одного инструмента, который что-либо удаляет, и ничто из хранилища не видно ни одному из них. Найти можно только людей, которым вы дали имя, — безымянные группы и скрытые люди недоступны.

Создание на его основе

Документация по API доступна на /api/v1/docs, описание в формате OpenAPI 3.1 — на /api/v1/openapi.json.

В imogen-sdk есть клиенты для пяти языков — TypeScript, Rust, Python, Swift и Kotlin. На 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}`),
})

Создание мобильного приложения

Каждый SDK включает OAuth-клиент, необходимый нативному приложению: Swift- и Kotlin-версии существуют именно для этого. Ничего не зашито жёстко: приложение регистрируется само, поэтому работает с любым imogen-сервером, который укажет пользователь.

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)

Загрузка идемпотентна по содержимому: повторная отправка фотографии, которая уже есть на сервере, возвращает существующий ресурс вместо сохранения второй копии, поэтому цикл синхронизации может быть простым и при этом корректным. Передайте deviceAssetId, и клиент будет знать, что уже отправлено, не ведя собственного журнала.

Сопряжение вместо запроса адреса сервера

Описанный выше процесс по-прежнему требует, чтобы приложение знало, к какому серверу обращаться, а самостоятельно размещённая библиотека находится по адресу, который выбрал её владелец. Вводить этот адрес на телефонной клавиатуре — худший момент при установке такого приложения, поэтому это делает браузер.

Настройки → УстройстваСопрячь устройство — здесь создаётся одноразовый билет и отображается в виде QR-кода, который содержит и URL сервера, и код. Приложение считывает квадрат и делает остальное:

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

Через камеру передаётся билет, а не токен. Он одноразовый, живёт пять минут и даёт ровно один код авторизации, привязанный к PKCE-челленджу, который никогда не покидал устройство, поэтому фотографии чужого экрана недостаточно. Полученный грант — обычный и отображается среди подключённых приложений, как и любой другой.

На той же странице билет доступен и в виде ссылки — для телефона, уже открывшего веб-интерфейс: по нажатию на неё сразу открывается приложение.

Разработка

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

Тесты выполняются против реального Postgres и реального HTTP-сервера, а не моков. Части, которые важно сделать правильно, — потоки OAuth, курсорная пагинация, конвейер обработки медиа — это как раз те части, в которых моки позволили бы ошибиться.

Структура

Пакет

Назначение

packages/server

Приложение на Hono: маршруты, аутентификация, конвейер обработки медиа, воркеры задач.

packages/web

React-PWA. Оно использует @imogen/sdk как любой сторонний клиент, благодаря чему SDK проверяется на практике.

packages/mcp

Мост через stdio для локальных агентов.

Клиентские библиотеки живут в собственном репозитории, imogen-sdk — TypeScript, Rust, Python, Swift и Kotlin, проверяемые по одному общему набору контрактных фикстур. @imogen/shared, Zod-схемы, по которым этот сервер производит валидацию и из которых генерирует свой документ OpenAPI, тоже живут там: это API-контракт, и контракту место вместе с клиентами, которые обязаны ему следовать.

packages/server/src/api/sdk-contract.test.ts — это сторона такой договорённости. Он поднимает настоящее приложение и прогоняет его через опубликованный TypeScript-клиент; это единственное место, где можно показать, что две половины согласуются.

Дизайн-документ находится в docs/superpowers/specs.


Пока не реализовано

Семантический поиск — поиск фотографии по её описанию — не реализован. Схема резервирует векторный столбец для активов, а поисковый индекс уже на месте, так что эта возможность может появиться без миграции, но сегодня поиск охватывает имена файлов, описания, места, метаданные камеры и людей, которым вы дали имена.

Также отсутствуют: обратное геокодирование (координаты показываются как координаты), транскодирование видео и хранилище S3. Драйвер хранилища — это интерфейс, так что добавление S3 станет локальным изменением, когда оно кому-то понадобится.

Группировка лиц работает, но имеет шероховатости, о которых стоит знать. Она хорошо распознаёт фронтальные, достаточно освещённые лица; профили, солнцезащитные очки, смазанность из-за движения и маленькие дети — чьи лица меняются быстрее, чем может уследить сохранённый усреднённый шаблон, — вот где она вас разочарует. Она скорее ошибается в сторону разделения одного человека на две группы, чем слияния двух людей, исходя из того, что первое исправляется одним кликом, а второе подшивает чьи-то фотографии под именем другого человека.

Лицензия

AGPL-3.0-or-later. Если вы запускаете модифицированный imogen как сервис, поделитесь изменениями.

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