# PhotoPrism® — Repository Guidelines **Last Updated:** December 8, 2025 ## Purpose This file tells automated coding agents (and humans) where to find the single sources of truth for building, testing, and contributing to this repository. Visit https://agents.md/ to learn more. ## Sources of Truth - Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile - Developer Guide – Setup: https://docs.photoprism.app/developer-guide/setup/ - Developer Guide – Tests: https://docs.photoprism.app/developer-guide/tests/ - Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md - Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md - REST API: https://docs.photoprism.dev/ (Swagger), https://docs.photoprism.app/developer-guide/api/ (Docs) - Code Maps: [`CODEMAP.md`](CODEMAP.md) (Backend/Go), [`frontend/CODEMAP.md`](frontend/CODEMAP.md) (Frontend/JS) - Packages: `README.md` files under `internal/`, `pkg/`, and `frontend/src/`, e.g. [`internal/photoprism/README.md`](internal/photoprism/README.md), [`internal/photoprism/batch/README.md`](internal/photoprism/batch/README.md), [`internal/config/README.md`](internal/config/README.md), [`internal/server/README.md`](internal/server/README.md), [`internal/api/README.md`](internal/api/README.md), [`internal/thumb/README.md`](internal/thumb/README.md), [`internal/ffmpeg/README.md`](internal/ffmpeg/README.md), and [`frontend/src/common/README.md`](frontend/src/common/README.md). - Face Detection & Embeddings: [`internal/ai/face/README.md`](internal/ai/face/README.md) - Vision Config & Engines: [`internal/ai/vision/README.md`](internal/ai/vision/README.md), [`internal/ai/vision/openai/README.md`](internal/ai/vision/openai/README.md), [`internal/ai/vision/ollama/README.md`](internal/ai/vision/ollama/README.md) > Quick Tip: to inspect GitHub issue details without leaving the terminal, run `curl -s https://api.github.com/repos/photoprism/photoprism/issues/`. ### Specifications, Versioning, & Writing Style - In the main repo, `specs/` and other directories may appear to be ignored because they are nested Git repositories; if so, change directories before staging or committing updates. - Availability: The `specs/` repository is private and is not guaranteed to be present in every clone or environment. Do not add `Makefile` targets in the main project that depend on `specs/` paths. When `specs/` is available, you MAY run its tools manually (e.g., `bash specs/scripts/lint-status.sh`), but the main repo must remain buildable without `specs/`. - If available, always use the latest spec version for a topic (highest `-vN`), as linked from `specs/README.md`. - Testing Guides: `specs/dev/backend-testing.md` (Backend/Go), `specs/dev/frontend-testing.md` (Frontend/JS) - Whenever the Change Management instructions for a document require it, publish changes as a new file with an incremented version suffix (e.g., `*-v3.md`) rather than overwriting the original file. - Older spec versions remain in the repo for historical reference but are not linked from the main TOC. Do not base new work on superseded files (e.g., `*-v1.md` when `*-v2.md` exists). - Auto-generated configuration and command references live under `specs/generated/`. Agents MUST NOT read, analyse, or modify anything in this directory; refer humans to `specs/generated/README.md` if regeneration is required. - Regenerate `NOTICE` files with `make notice` when dependencies change (e.g., updates to `go.mod`, `go.sum`, `package-lock.json`, or other lockfiles). Do not edit `NOTICE` or `frontend/NOTICE` manually. - When writing CLI examples or scripts, place option flags before positional arguments unless the command requires a different order. > Document headings must use **Title Case** (in APA or AP style) across Markdown files to keep generated navigation and changelogs consistent. Always spell the product name as `PhotoPrism`; this proper noun is an exception to generic naming rules. ## Safety & Data - If `git status` shows unexpected changes, assume a human might be editing; if you think you caused them, ask for permission before using reset commands like `git checkout` or `git reset`. - Do not run `git config` (global or repo-level); changing Git configuration is prohibited for agents. - Do not run destructive commands against production data. Prefer ephemeral volumes and test fixtures for acceptance tests. - Never commit secrets, local configurations, or cache files. Use environment variables or a local `.env`. - Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are ignored in `.gitignore` and `.dockerignore`. - Prefer using existing caches, workers, and batching strategies referenced in code and `Makefile`. - Consider memory/CPU impact of changes; only suggest benchmarks or profiling when justified. > If anything in this file conflicts with the `Makefile` or Sources of Truth, **ask** for clarification before proceeding. ## Project Structure & Languages - Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite - Package boundaries: Code in `pkg/*` MUST NOT import from `internal/*`. - If you need access to config/entity/DB, put new code in a package under `internal/` instead of `pkg/`. - GORM field naming: When adding struct fields that include uppercase abbreviations (e.g., `LabelNSFW`, `UserID`, `URLHash`), set an explicit `gorm:"column:"` tag so column names stay consistent (`label_nsfw`, `user_id`, `url_hash` instead of split-letter variants). - Frontend: Vue 3 + Vuetify 3 (`frontend/`) - Docker/compose for dev/CI; Traefik is used for local TLS (`*.localssl.dev`) ### Web Templates & Shared Assets - HTML entrypoints live under `assets/templates/`; key files are `index.gohtml`, `app.gohtml`, `app.js.gohtml`, and `splash.gohtml`. The browser check logic resides in `assets/static/js/browser-check.js` and is included via `app.js.gohtml`; it performs capability checks (Promise, fetch, AbortController, `script.noModule`, etc.) before the main bundle executes. - To preserve the fallback messaging, keep the `