| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 1 | 15 | 13 | 3% |
| Commands | 12 | 18 | 12 | 29% |
| Section tags | 8 | 4 | 1 | 62% |
What each file covers
Sections
1 shared · 15 only in A · 13 only in B- − PhotoPrism Repository Guidelines
- − Sources of Truth
- − Subtree Guides
- − Local Agent Progress
- − Style Notes
- − Commit Messages
- − GitHub Issues
- − Specifications & Documentation
- − Safety & Data
- − Project Layout & Shared Rules
- − JS/Go Code Comments
- − Agent Runtime
- − Build, Format & Test
- − Continuous Integration
- − Container Image Builds
- + Instructions for GitHub Copilot
- + Single Sources of Truth (SOT)
- + Build & Run (local dev; use Makefile first)
- + Tests & Lint
- + Project Structure & Languages
- + Code Review Instructions (for Copilot)
- + Style & Patterns
- + Commits & Pull Requests
- + Performance & Reliability
- + When Unsure
- + References To Help Copilot Answer Questions
- + Output Expectations
- + Safety Checklist Before Proposing a CLI Command
- Purpose
Commands
12 shared · 18 only in A · 12 only in B- − git status
- − git config
- − npm exec --yes <agent> -- --help
- − npx <agent> ...
- − npm ci
- − npm install
- − make
- − npm rebuild --ignore-scripts=false <pkg>
- − npm rebuild
- − docker compose up -d
- − docker compose exec photoprism ./photoprism help
- − docker compose exec -u "$(id -u):$(id -g)" photoprism <command>
- − make terminal
- − docker compose --profile=all down --remove-orphans
- − make down
- − make lint
- − make check-make-help
- − go test ./path/to/pkg -run Name -count=1
- + make test-js
- + make vitest-watch
- + make vitest-coverage
- + make test-go
- + make test-short
- + go test ./internal/<pkg> -run '<TestName>' -count=1
- + make lint-go
- + make fmt-js
- + make lint-js
- + make fmt-go swag-fmt swag
- + go.mod
- + go.sum
- make notice
- make fmt-go
- make help
- make list
- make docker-build
- docker compose up
- docker compose logs -f --tail=100 photoprism
- make dep
- make build-js
- make build-go
- make watch-js
- make test
Section tags
8 shared · 4 only in A · 1 only in B- − setup
- − testing-strategy
- − security
- − docs
- + performance
- build
- test
- lint-format
- code-style
- architecture
- git-pr
- do-not
- agent-behaviour
Line diff
photoprism/photoprism · AGENTS.md
@@ −1 @@
1# PhotoPrism Repository Guidelines
2
3**Last Updated:** July 28, 2026
4
5## Purpose
6
7Entry point for agents and humans.
8
9## Sources of Truth
10
11- Makefile: https://github.com/photoprism/photoprism/blob/develop/Makefile
12- Setup guide: https://docs.photoprism.app/developer-guide/setup/
13- Test guide: https://docs.photoprism.app/developer-guide/tests/
14- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
15- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
16- REST API: https://docs.photoprism.dev/ and https://docs.photoprism.app/developer-guide/api/
17- Code maps: [`CODEMAP.md`](CODEMAP.md), [`frontend/CODEMAP.md`](frontend/CODEMAP.md)
18- Package docs: `README.md` files under `internal/`, `pkg/`, `frontend/`, and `frontend/src/`
19- Frontend dependency pins, override layer, and orphan-audit pattern: [`frontend/README.md`](frontend/README.md) (read before bumping any non-caret pin or adding/removing a top-level dep)
20- AI/Vision docs: [`internal/ai/face/README.md`](internal/ai/face/README.md), [`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)
21- Glossary: [`GLOSSARY.md`](GLOSSARY.md)
22- When dependencies change, regenerate `NOTICE` files with `make notice`; do not edit `NOTICE` or `frontend/NOTICE` manually.
23
24## Subtree Guides
25
26- [`internal/AGENTS.md`](internal/AGENTS.md): internal Go rules.
27- [`internal/api/AGENTS.md`](internal/api/AGENTS.md): API rules.
28- [`internal/config/AGENTS.md`](internal/config/AGENTS.md): config rules.
29- [`internal/commands/AGENTS.md`](internal/commands/AGENTS.md): CLI rules.
30- [`internal/photoprism/AGENTS.md`](internal/photoprism/AGENTS.md): import and index rules.
31- [`internal/service/cluster/AGENTS.md`](internal/service/cluster/AGENTS.md): cluster rules.
32- [`frontend/AGENTS.md`](frontend/AGENTS.md): frontend rules.
33- [`pkg/AGENTS.md`](pkg/AGENTS.md): `pkg/*` security and test rules.
34
35Optional nested repositories such as `plus/`, `pro/`, `portal/`, and `specs/` may contain their own `AGENTS.md` files. When present, treat those files as additional directory-local guidance.
36
37## Local Agent Progress
38
39- Use `.agents/TODO.md` for actionable tasks and `.agents/DONE.md` for completed work.
40- These files are local workflow aids and may not exist in every workspace.
41
42## Style Notes
43
44### Commit Messages
45
46- Use concise imperative subjects with a one-word prefix, for example `Config: Add tests for "darktable-cli" path detection`.
47- Append issue or PR IDs when relevant.
48- Commit messages must not exceed 80 characters.
49
50### GitHub Issues
51
52- Titles MUST be concise, imperative, and start with one capitalized prefix plus `: `, for example `Search: Add filter for RAW image formats`.
53- Descriptions MUST begin with a one-sentence bold user story: `**As a <role>, I want <goal>, so that <outcome>.**`
54- Use level-3 Markdown headings for sections within issue descriptions, for example `### Acceptance Criteria`.
55- Follow with behavior, rationale, technical considerations, and constraints.
56- End with `- [ ]` checklist items for the acceptance criteria, each using `MUST`, `SHOULD`, or `MAY`.
57 - Keep the checklist current: once the work for a criterion is implemented **and verified**, mark it done (`- [x]`).
58 - Leave items that are unverified, not yet implemented, or skipped optional (`MAY`) enhancements unchecked.
59 - An issue is complete only when every `MUST` is checked; never tick a box on the strength of a plan alone or an unrun test.
60 - When referencing an issue from a commit that fulfills some of its criteria, update the matching boxes first.
61- Agents MUST create, edit, close, reopen, relabel, or otherwise modify GitHub issues only when explicitly requested by the user.
62
63### Specifications & Documentation
64
65- Markdown headings use a Chicago-style title case, with additional code- and path-aware normalization rules (see *Title Case rules* below). Always spell the product name as `PhotoPrism`.
66- Put option flags before positional arguments unless the command requires another order.
67- Use RFC 3339 UTC timestamps and valid ID, UID, and UUID examples in docs and tests.
68- The nested `specs/` repository may be absent. Do not add main-repo `Makefile` targets that depend on it; when present, you may run its tools manually.
69- Testing guides live at `specs/dev/backend-testing.md` and `specs/dev/frontend-testing.md`.
70- Do not read, analyze, or modify `specs/generated/`; refer humans to `specs/generated/README.md` when regeneration is needed.
71- Refresh `**Last Updated:**` when you change document contents, but leave it unchanged for whitespace-only or formatting-only edits.
72- Nested Git repositories may appear ignored; change into them before staging or committing updates.
73
74Title Case rules (Chicago-style, with code- and path-aware normalization):
75- Capitalize the first word, the first word after a colon, dash, or end punctuation, and all major words, including the second part of a hyphenated major word.
76- Lowercase only articles, short conjunctions, and short prepositions of three letters or fewer when they are not in one of those positions.
77- Preserve known acronyms (for example, API, CLI, HTTP, JSON) and slash-separated acronym groups (for example, CSV/TSV) as uppercase.
78- Preserve RFC 2119 / RFC 8174 normative keywords (MUST, SHOULD, MAY, SHALL, REQUIRED, RECOMMENDED, OPTIONAL) as uppercase when used in their normative sense.
79- Preserve inline code spans (`` `foo` ``), file paths (e.g. `docs/foo-bar.md`), and slash commands (e.g. `/grill-me`) verbatim; do not recase their contents.
80- Use `&` instead of `And`/`Or` in headings.
81
82## Safety & Data
83
84- If `git status` shows unexpected changes, assume a human may be editing; ask before using reset-style commands.
85- Do not run `git config` at either the global or repository level.
86- Do not run destructive commands against production data; prefer ephemeral volumes and test fixtures for acceptance tests.
87- Never commit secrets, local configurations, or cache files; use environment variables or a local `.env`.
88- Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are ignored in `.gitignore` and `.dockerignore`.
89- Prefer existing caches, workers, and batching strategies already referenced by the code and `Makefile`.
90- Consider CPU and memory impact; only suggest profiling or benchmarks when justified.
91- If anything here conflicts with the `Makefile` or the sources of truth, ask for clarification before proceeding.
92
93## Project Layout & Shared Rules
94
95- Backend: Go in `internal/`, `pkg/`, and `cmd/`, backed by MariaDB or SQLite.
96- Frontend: Vue 3 plus Vuetify 3 under `frontend/`.
97- Local dev and CI use Docker Compose; Traefik provides local TLS via `*.localssl.dev`.
98- Code in `pkg/*` must not import from `internal/*`. If you need config, entity, or DB access, add code under `internal/`.
99- Shared Go rules:
100 - After Go edits, run `make fmt-go` and keep `gofmt` tab indentation.
101 - Every added/modified Go function, including unexported helpers, must have focused test coverage in the corresponding `*_test.go` files; update existing tests or add new ones as needed.
102 - Every Go package must contain a root `<package>.go` file with the standard license header and a short package description comment.
103 - Use `pkg/fs` permission constants: `fs.ModeDir`, `fs.ModeFile`, `fs.ModeConfigFile`, `fs.ModeSecretFile`, and `fs.ModeBackupFile`.
104 - When importing the stdlib `io/fs`, alias it to avoid collisions, for example `iofs "io/fs"` or `gofs "io/fs"`.
105 - Do not pass stdlib `io/fs` mode flags where permission bits are expected.
106 - Prefer `filepath.Join` for filesystem paths and `path.Join` only for URL paths.
107 - Normalize slash-based logical paths stored in DB, config, or API payloads with `clean.SlashPath(...)`.
108- Shared JS/Vue rules:
109 - Added/modified JavaScript functions, including helpers, should be tested whenever practical; update existing tests or add new ones as needed.
110 - Added/modified Vue components should have component-test coverage, and existing component tests should be updated as needed when behavior changes.
111- When adding a metadata source such as `SrcOllama` or `SrcOpenAI`, update both `internal/entity/src.go` and `frontend/src/common/util.js` so backend and UI stay aligned.
112
113### JS/Go Code Comments
114
115A doc comment is **required** for every function (including unexported helpers), as well as for every non-trivial Vue `methods:` / `computed:` / watcher:
116- Keep comments **compact** and default to one line for "what" in the format `// Name does X.`. Skip trivial getters (`isOpen: () => this.open`).
117- Add 1-2 follow-up lines (`// …`) **only** if the "why" is non-obvious: a hidden invariant, a workaround that would otherwise be undone by a future cleanup, a contract a reader can't infer from the code. If readers can infer the "why" from the function body or a nearby line, then omit it.
118- Multi-paragraph explanations belong in `specs/`, package `README.md` files, or GitHub issues — never in the source itself.
119
120Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period. For short examples in comments, indent code instead of using backticks.
121
122Use US English spelling in all code comments (`parameterized`, `behavior`, `color`, `serialize`, `normalize`, `optimize`, …) — not the British `-ised`/`-our`/`-re` variants.
123
124> **Don't include in code comments:** Issue / PR numbers, "previously…" history, alternatives considered, what the function used to do, references to old commits, names of subsequent reviewers, or any narrative that names the change rather than the steady-state behavior. That context belongs in commit messages, specs, or handover notes.
125
126## Agent Runtime
127
128- Detect container mode by checking for `/.dockerenv`.
129- If the repo path is `/go/src/github.com/photoprism/photoprism` and `/.dockerenv` is absent, treat the environment as host mode with a bind mount and prefer host-side Docker commands.
130- Bash check: `[ -f "/.dockerenv" ] && echo container || echo host`
131- Node.js check: `require("fs").existsSync("/.dockerenv")`
132- Inside the container, prefer `npm exec --yes <agent> -- --help` or `npx <agent> ...`; if a global npm install is unavoidable, install it only inside the container.
133- The `photoprism/develop` base image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so `npm ci`/`npm install` via `make` targets skip install scripts out of the box. When running npm directly in an environment that does not set or inherit that default, pass `--ignore-scripts` explicitly to mitigate supply-chain attacks. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` is a silent no-op wherever the env default is active.
134- On the host, use the vendor-recommended install method and run from the repository root so agent discovery sees this file.
135
136## Build, Format & Test
137
138- Run `make help` for an overview of the most common targets, and `make list` to see all of them.
139- Host mode:
140 - `make docker-build`
141 - `docker compose up` or `docker compose up -d`
142 - `docker compose logs -f --tail=100 photoprism`
143 - `docker compose exec photoprism ./photoprism help`
144 - `docker compose exec -u "$(id -u):$(id -g)" photoprism <command>` to avoid root-owned files
145 - `make terminal`
146 - `docker compose --profile=all down --remove-orphans` or `make down`
147- Container mode:
148 - `make dep`
149 - `make build-js` and `make build-go`
150 - `make watch-js` or `cd frontend && npm run watch`
151 - `./photoprism start`
152 - Local URLs: `http://localhost:2342/` and, with Traefik, `https://app.localssl.dev/`
153 - Local compose defaults to `admin` / `photoprism`; inspect `compose.yaml` if they differ.
154 - Do not use the Docker CLI inside the container; manage Compose from the host instead.
155- The public CLI name is always `photoprism`; development-only side-by-side binaries may use edition-specific names.
156- Our command examples assume a Linux or Unix shell on 64-bit AMD64 or ARM64; see the Developer Guide FAQ for Windows-specific notes.
157
158Formatting and test entry points:
159- Full suite: `make test`, `make lint`
160- After renaming or removing a Makefile target, run `make check-make-help` (also included in `make lint`) so that no `make help` overview keeps advertising it.
161- Go-specific lint, format, and package-test rules live in [`internal/AGENTS.md`](internal/AGENTS.md).
162- Frontend lint, Vitest, acceptance, and Playwright rules live in [`frontend/AGENTS.md`](frontend/AGENTS.md).
163- Go tests live next to their sources; use PascalCase `t.Run(...)` names for related subtests. Keep consecutive subtests inside the same `Test*` function back-to-back without blank lines so the cases read as a compact table; reserve blank lines for separating distinct setup blocks.
164- Do not run multiple test commands in parallel; suites share fixtures, assets, and database state.
165- Prefer focused test runs such as `go test ./path/to/pkg -run Name -count=1` while iterating.
166- Use `mariadb -D photoprism` inside the dev shell when you need to inspect MariaDB state directly.
167- Run `shellcheck <file>` on edited shell scripts, or use the corresponding `make` target.
168
169### Continuous Integration
170
171- **GitHub Actions is not enabled for this repository.** The workflow files under `.github/workflows/` do not execute, so pushes and pull requests produce no check runs. Treat them as dormant configuration: do not diagnose the absence of runs as a broken workflow, do not propose enabling Actions, and do not add workflows or bot configuration that assumes they will run. Ask a maintainer before changing anything under `.github/workflows/`.
172- The `make` targets above are the authoritative build, format, and test gate. Run them locally and report the output rather than relying on a hosted runner.
173
174### Container Image Builds
175
176- **Never mix Debian and Ubuntu `apt` repositories in the same image:**
177 - Don't add a Debian source to an Ubuntu base (or vice versa) to install a single missing package — the transitive deps drift, apt's solver pulls newer libraries from the foreign distro, and other build steps in the same `RUN` (e.g. `install-libheif.sh` running `apt-get install libavcodec-dev`) silently link against the wrong soname.
178 - Symptoms surface much later as `dlopen: libfoo.so.N: cannot open shared object file` at image runtime, with the binary referencing a soname that exists only in the foreign distro.
179 - If a package isn't available in the host distro's repos, prefer (a) a same-distro PPA / backports source, (b) a vendor-supplied .deb (e.g. Google Chrome from `dl.google.com`), or (c) a from-source build pinned to a known version.
180
photoprism/photoprism · .github/copilot-instructions.md
@@ +1 @@
1# Instructions for GitHub Copilot
2
3**Last Updated:** July 28, 2026
4
5## Purpose
6
7- Provide Copilot with the single sources of truth for building, testing, and contributing to PhotoPrism.
8- Improve PR reviews and code suggestions by aligning them with our documented workflows and style.
9- Path-specific rules that apply on top of this file live in `.github/instructions/*.instructions.md`.
10
11## Single Sources of Truth (SOT)
12
13- Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile
14- Developer Guide – Setup: https://docs.photoprism.app/developer-guide/setup/
15- Developer Guide – Tests: https://docs.photoprism.app/developer-guide/tests/
16- Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
17- Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
18- REST API (Swagger): https://docs.photoprism.dev/
19- REST API Guide: https://docs.photoprism.app/developer-guide/api/
20- Agents reference for tools/commands: https://github.com/photoprism/photoprism/blob/develop/AGENTS.md
21- Code maps: https://github.com/photoprism/photoprism/blob/develop/CODEMAP.md (backend) and https://github.com/photoprism/photoprism/blob/develop/frontend/CODEMAP.md (frontend)
22- Terminology: https://github.com/photoprism/photoprism/blob/develop/GLOSSARY.md
23
24## Build & Run (local dev; use Makefile first)
25
26- Show common tasks: `make help` (`make list` shows all targets)
27- Build local image: `make docker-build`
28- Start dev env: `docker compose up` (add `-d` for detached, or run `make up`)
29- Logs: `docker compose logs -f --tail=100 photoprism`
30- Open app: http://localhost:2342/ (HTTP) / https://app.localssl.dev/ (TLS via Traefik when enabled)
31- From the dev container:
32 - Install deps: `make dep`
33 - Build frontend: `make build-js` (or `cd frontend && npm run build`)
34 - Build backend: `make build-go`
35 - Watch frontend: `make watch-js` (stop with Ctrl+C)
36 - Run server binary: `./photoprism start`
37
38## Tests & Lint
39
40- Full tests: `make test`
41- Frontend tests (Vitest): `make test-js` (watch: `make vitest-watch`, coverage: `make vitest-coverage`)
42- Backend tests: `make test-go` (slow); `make test-short` for a fast parallel run
43- Targeted Go tests: `go test ./internal/<pkg> -run '<TestName>' -count=1`
44- Formatting and linting:
45 - Go: `make fmt-go` (gofmt + goimports) and `make lint-go` (golangci-lint)
46 - JS/Vue: `make fmt-js` and `make lint-js`. ESLint owns JS and Vue; Prettier owns CSS/SCSS/SASS only. ESLint does not run Prettier, so do not propose reflowing JS to satisfy Prettier.
47- Swagger: after changing API handlers or annotations, run `make fmt-go swag-fmt swag`; never edit `internal/api/swagger.json` by hand.
48- Dependencies: when `go.mod`, `go.sum`, or `package-lock.json` change, regenerate the license reports with `make notice`; never edit `NOTICE` or `frontend/NOTICE` manually.
49
50## Project Structure & Languages
51
52- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
53- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
54- Docker/compose for dev/CI; Traefik used for local TLS in dev profile when enabled.
55- A maintainer's working copy may contain private subdirectories (`plus/`, `pro/`, `portal/`, `specs/`) that are not part of this repository. Never reference their paths from public artifacts such as pull request descriptions, issue comments, or code comments — external readers only see a broken link.
56
57## Code Review Instructions (for Copilot)
58
59- Respect SOT above; do not invent flags, env vars, or Compose options. If a command/env var is not in the docs/Makefile/CLI help, say "not documented" and suggest checking the SOT.
60- Prefer minimal, surgical diffs. Propose changes as concrete patches and reference the relevant Makefile target or doc section.
61- Before suggesting refactors, check tests and build tasks exist and can pass with the change. If tests are missing, suggest specific Vitest/Go test snippets.
62- Security: never suggest committing secrets; prefer env vars and `.env` in dev only. Point to SECURITY.md for disclosures.
63- Data safety: never run or recommend destructive CLI operations in examples without explicit backups and `--yes`. Avoid `photoprism reset`, `photoprism users reset`, `photoprism auth reset`, or `photoprism audit reset` in PR comments unless the change is specifically about those commands; if unavoidable, add bold warnings and backup steps.
64- Database/schema: if a change touches persistence, check for migrations and mention `photoprism migrate` / `migrations` commands.
65- API changes: align with the REST API docs/spec; include curl examples only if they match current endpoints and auth notes.
66- UX/i18n: keep UI strings concise, translatable, and consistent; avoid hard-coded language constructs; prefer existing patterns/components.
67
68## Style & Patterns
69
70- Go: idiomatic Go, clear error handling, small functions, packages with focused responsibilities. Keep the public surface minimal.
71 - Every added function, including unexported helpers and helpers extracted by a refactor, needs focused coverage in a sibling `*_test.go`.
72 - Code in `pkg/*` must not import from `internal/*`; new code that needs config, entity, or DB access belongs under `internal/`.
73 - Use the permission constants in `pkg/fs` (`fs.ModeDir`, `fs.ModeFile`, `fs.ModeConfigFile`, `fs.ModeSecretFile`) instead of literal file modes.
74 - Doc comments start with the name and stay compact — one line for the "what", plus a line or two only when the "why" cannot be inferred from the code. No issue numbers or change history in comments.
75- Vue/JS: Options API only. Do not introduce TypeScript (no `.ts` files, no `<script lang="ts">`), Composition API, or `<script setup>`.
76 - Shared state lives in reactive singleton modules under `src/common/` and `src/app/`. Do not propose Vuex or Pinia.
77 - Every user-visible string must go through `$gettext`, so it reaches `frontend/src/locales/translations.pot`. Standardized technical identifiers (`Client ID`, `OIDC`, `UUID`) stay literal.
78 - Prefer existing components and model methods over raw `$api` calls in components.
79- Config & flags: suggest `photoprism --help`, `photoprism show config-options` or `photoprism show config-yaml` to verify names before using them.
80
81## Commits & Pull Requests
82
83- Commit subjects use the imperative mood with a one-word scope prefix, for example `Config: Add tests for "darktable-cli" path detection`, and must not exceed 80 characters.
84- Reference related issue or PR IDs in the message when applicable, for example `Docker: Use two stage build to reduce image size #123 #5632`.
85- Do not add AI-authorship trailers such as `Co-Authored-By: Copilot` — this repository uses no commit trailers.
86- Issue titles follow the same prefix style; descriptions open with a bold user story (`**As a <role>, I want <goal>, so that <outcome>.**`) and close with a checklist of acceptance criteria using MUST, SHOULD, or MAY.
87- Commit messages, code comments, and public issue or PR text must not describe exploitable details of a security fix; present such changes as general hardening.
88
89## Performance & Reliability
90
91- Prefer using existing caches, workers, and batching strategies referenced in code and Makefile. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
92
93## When Unsure
94
95- Ask for the exact Makefile target or doc link you need, then proceed. Defer to SOT if any conflict arises.
96
97## References To Help Copilot Answer Questions
98
99- Show supported formats/filters: run `photoprism show file-formats` and `photoprism show search-filters` (use results rather than guessing).
100- For CI/dev containers, assume a Linux/Unix shell on amd64 or arm64 by default; for Windows specifics, link https://docs.photoprism.app/developer-guide/faq/
101
102## Output Expectations
103
104- Prefer short, actionable comments with code blocks that pass tests locally: `make test-js` (frontend) / `make test-go` (backend)
105- If a suggestion requires additional context (e.g., DB access, external service), call it out explicitly.
106
107## Safety Checklist Before Proposing a CLI Command
108
109- Include a dry-run or non-destructive variant if possible.
110- Recommend creating/using backups before any reset/migrate.
111
@@ −1 +1 @@
1−# PhotoPrism Repository Guidelines
1+# Instructions for GitHub Copilot
22
33 **Last Updated:** July 28, 2026
44
55 ## Purpose
66
7−Entry point for agents and humans.
7+- Provide Copilot with the single sources of truth for building, testing, and contributing to PhotoPrism.
8+- Improve PR reviews and code suggestions by aligning them with our documented workflows and style.
9+- Path-specific rules that apply on top of this file live in `.github/instructions/*.instructions.md`.
810
9−## Sources of Truth
11+## Single Sources of Truth (SOT)
1012
11−- Makefile: https://github.com/photoprism/photoprism/blob/develop/Makefile
12−- Setup guide: https://docs.photoprism.app/developer-guide/setup/
13−- Test guide: https://docs.photoprism.app/developer-guide/tests/
13+- Makefile targets (always prefer existing targets): https://github.com/photoprism/photoprism/blob/develop/Makefile
14+- Developer Guide – Setup: https://docs.photoprism.app/developer-guide/setup/
15+- Developer Guide – Tests: https://docs.photoprism.app/developer-guide/tests/
1416 - Contributing: https://github.com/photoprism/photoprism/blob/develop/CONTRIBUTING.md
1517 - Security: https://github.com/photoprism/photoprism/blob/develop/SECURITY.md
16−- REST API: https://docs.photoprism.dev/ and https://docs.photoprism.app/developer-guide/api/
17−- Code maps: [`CODEMAP.md`](CODEMAP.md), [`frontend/CODEMAP.md`](frontend/CODEMAP.md)
18−- Package docs: `README.md` files under `internal/`, `pkg/`, `frontend/`, and `frontend/src/`
19−- Frontend dependency pins, override layer, and orphan-audit pattern: [`frontend/README.md`](frontend/README.md) (read before bumping any non-caret pin or adding/removing a top-level dep)
20−- AI/Vision docs: [`internal/ai/face/README.md`](internal/ai/face/README.md), [`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)
21−- Glossary: [`GLOSSARY.md`](GLOSSARY.md)
22−- When dependencies change, regenerate `NOTICE` files with `make notice`; do not edit `NOTICE` or `frontend/NOTICE` manually.
18+- REST API (Swagger): https://docs.photoprism.dev/
19+- REST API Guide: https://docs.photoprism.app/developer-guide/api/
20+- Agents reference for tools/commands: https://github.com/photoprism/photoprism/blob/develop/AGENTS.md
21+- Code maps: https://github.com/photoprism/photoprism/blob/develop/CODEMAP.md (backend) and https://github.com/photoprism/photoprism/blob/develop/frontend/CODEMAP.md (frontend)
22+- Terminology: https://github.com/photoprism/photoprism/blob/develop/GLOSSARY.md
2323
24−## Subtree Guides
24+## Build & Run (local dev; use Makefile first)
2525
26−- [`internal/AGENTS.md`](internal/AGENTS.md): internal Go rules.
27−- [`internal/api/AGENTS.md`](internal/api/AGENTS.md): API rules.
28−- [`internal/config/AGENTS.md`](internal/config/AGENTS.md): config rules.
29−- [`internal/commands/AGENTS.md`](internal/commands/AGENTS.md): CLI rules.
30−- [`internal/photoprism/AGENTS.md`](internal/photoprism/AGENTS.md): import and index rules.
31−- [`internal/service/cluster/AGENTS.md`](internal/service/cluster/AGENTS.md): cluster rules.
32−- [`frontend/AGENTS.md`](frontend/AGENTS.md): frontend rules.
33−- [`pkg/AGENTS.md`](pkg/AGENTS.md): `pkg/*` security and test rules.
26+- Show common tasks: `make help` (`make list` shows all targets)
27+- Build local image: `make docker-build`
28+- Start dev env: `docker compose up` (add `-d` for detached, or run `make up`)
29+- Logs: `docker compose logs -f --tail=100 photoprism`
30+- Open app: http://localhost:2342/ (HTTP) / https://app.localssl.dev/ (TLS via Traefik when enabled)
31+- From the dev container:
32+ - Install deps: `make dep`
33+ - Build frontend: `make build-js` (or `cd frontend && npm run build`)
34+ - Build backend: `make build-go`
35+ - Watch frontend: `make watch-js` (stop with Ctrl+C)
36+ - Run server binary: `./photoprism start`
3437
35−Optional nested repositories such as `plus/`, `pro/`, `portal/`, and `specs/` may contain their own `AGENTS.md` files. When present, treat those files as additional directory-local guidance.
38+## Tests & Lint
3639
37−## Local Agent Progress
40+- Full tests: `make test`
41+- Frontend tests (Vitest): `make test-js` (watch: `make vitest-watch`, coverage: `make vitest-coverage`)
42+- Backend tests: `make test-go` (slow); `make test-short` for a fast parallel run
43+- Targeted Go tests: `go test ./internal/<pkg> -run '<TestName>' -count=1`
44+- Formatting and linting:
45+ - Go: `make fmt-go` (gofmt + goimports) and `make lint-go` (golangci-lint)
46+ - JS/Vue: `make fmt-js` and `make lint-js`. ESLint owns JS and Vue; Prettier owns CSS/SCSS/SASS only. ESLint does not run Prettier, so do not propose reflowing JS to satisfy Prettier.
47+- Swagger: after changing API handlers or annotations, run `make fmt-go swag-fmt swag`; never edit `internal/api/swagger.json` by hand.
48+- Dependencies: when `go.mod`, `go.sum`, or `package-lock.json` change, regenerate the license reports with `make notice`; never edit `NOTICE` or `frontend/NOTICE` manually.
3849
39−- Use `.agents/TODO.md` for actionable tasks and `.agents/DONE.md` for completed work.
40−- These files are local workflow aids and may not exist in every workspace.
50+## Project Structure & Languages
4151
42−## Style Notes
52+- Backend: Go (`internal/`, `pkg/`, `cmd/`) + MariaDB/SQLite
53+- Frontend: Vue 3 + Vuetify 3 (`frontend/`)
54+- Docker/compose for dev/CI; Traefik used for local TLS in dev profile when enabled.
55+- A maintainer's working copy may contain private subdirectories (`plus/`, `pro/`, `portal/`, `specs/`) that are not part of this repository. Never reference their paths from public artifacts such as pull request descriptions, issue comments, or code comments — external readers only see a broken link.
4356
44−### Commit Messages
57+## Code Review Instructions (for Copilot)
4558
46−- Use concise imperative subjects with a one-word prefix, for example `Config: Add tests for "darktable-cli" path detection`.
47−- Append issue or PR IDs when relevant.
48−- Commit messages must not exceed 80 characters.
59+- Respect SOT above; do not invent flags, env vars, or Compose options. If a command/env var is not in the docs/Makefile/CLI help, say "not documented" and suggest checking the SOT.
60+- Prefer minimal, surgical diffs. Propose changes as concrete patches and reference the relevant Makefile target or doc section.
61+- Before suggesting refactors, check tests and build tasks exist and can pass with the change. If tests are missing, suggest specific Vitest/Go test snippets.
62+- Security: never suggest committing secrets; prefer env vars and `.env` in dev only. Point to SECURITY.md for disclosures.
63+- Data safety: never run or recommend destructive CLI operations in examples without explicit backups and `--yes`. Avoid `photoprism reset`, `photoprism users reset`, `photoprism auth reset`, or `photoprism audit reset` in PR comments unless the change is specifically about those commands; if unavoidable, add bold warnings and backup steps.
64+- Database/schema: if a change touches persistence, check for migrations and mention `photoprism migrate` / `migrations` commands.
65+- API changes: align with the REST API docs/spec; include curl examples only if they match current endpoints and auth notes.
66+- UX/i18n: keep UI strings concise, translatable, and consistent; avoid hard-coded language constructs; prefer existing patterns/components.
4967
50−### GitHub Issues
68+## Style & Patterns
5169
52−- Titles MUST be concise, imperative, and start with one capitalized prefix plus `: `, for example `Search: Add filter for RAW image formats`.
53−- Descriptions MUST begin with a one-sentence bold user story: `**As a <role>, I want <goal>, so that <outcome>.**`
54−- Use level-3 Markdown headings for sections within issue descriptions, for example `### Acceptance Criteria`.
55−- Follow with behavior, rationale, technical considerations, and constraints.
56−- End with `- [ ]` checklist items for the acceptance criteria, each using `MUST`, `SHOULD`, or `MAY`.
57− - Keep the checklist current: once the work for a criterion is implemented **and verified**, mark it done (`- [x]`).
58− - Leave items that are unverified, not yet implemented, or skipped optional (`MAY`) enhancements unchecked.
59− - An issue is complete only when every `MUST` is checked; never tick a box on the strength of a plan alone or an unrun test.
60− - When referencing an issue from a commit that fulfills some of its criteria, update the matching boxes first.
61−- Agents MUST create, edit, close, reopen, relabel, or otherwise modify GitHub issues only when explicitly requested by the user.
70+- Go: idiomatic Go, clear error handling, small functions, packages with focused responsibilities. Keep the public surface minimal.
71+ - Every added function, including unexported helpers and helpers extracted by a refactor, needs focused coverage in a sibling `*_test.go`.
72+ - Code in `pkg/*` must not import from `internal/*`; new code that needs config, entity, or DB access belongs under `internal/`.
73+ - Use the permission constants in `pkg/fs` (`fs.ModeDir`, `fs.ModeFile`, `fs.ModeConfigFile`, `fs.ModeSecretFile`) instead of literal file modes.
74+ - Doc comments start with the name and stay compact — one line for the "what", plus a line or two only when the "why" cannot be inferred from the code. No issue numbers or change history in comments.
75+- Vue/JS: Options API only. Do not introduce TypeScript (no `.ts` files, no `<script lang="ts">`), Composition API, or `<script setup>`.
76+ - Shared state lives in reactive singleton modules under `src/common/` and `src/app/`. Do not propose Vuex or Pinia.
77+ - Every user-visible string must go through `$gettext`, so it reaches `frontend/src/locales/translations.pot`. Standardized technical identifiers (`Client ID`, `OIDC`, `UUID`) stay literal.
78+ - Prefer existing components and model methods over raw `$api` calls in components.
79+- Config & flags: suggest `photoprism --help`, `photoprism show config-options` or `photoprism show config-yaml` to verify names before using them.
6280
63−### Specifications & Documentation
81+## Commits & Pull Requests
6482
65−- Markdown headings use a Chicago-style title case, with additional code- and path-aware normalization rules (see *Title Case rules* below). Always spell the product name as `PhotoPrism`.
66−- Put option flags before positional arguments unless the command requires another order.
67−- Use RFC 3339 UTC timestamps and valid ID, UID, and UUID examples in docs and tests.
68−- The nested `specs/` repository may be absent. Do not add main-repo `Makefile` targets that depend on it; when present, you may run its tools manually.
69−- Testing guides live at `specs/dev/backend-testing.md` and `specs/dev/frontend-testing.md`.
70−- Do not read, analyze, or modify `specs/generated/`; refer humans to `specs/generated/README.md` when regeneration is needed.
71−- Refresh `**Last Updated:**` when you change document contents, but leave it unchanged for whitespace-only or formatting-only edits.
72−- Nested Git repositories may appear ignored; change into them before staging or committing updates.
83+- Commit subjects use the imperative mood with a one-word scope prefix, for example `Config: Add tests for "darktable-cli" path detection`, and must not exceed 80 characters.
84+- Reference related issue or PR IDs in the message when applicable, for example `Docker: Use two stage build to reduce image size #123 #5632`.
85+- Do not add AI-authorship trailers such as `Co-Authored-By: Copilot` — this repository uses no commit trailers.
86+- Issue titles follow the same prefix style; descriptions open with a bold user story (`**As a <role>, I want <goal>, so that <outcome>.**`) and close with a checklist of acceptance criteria using MUST, SHOULD, or MAY.
87+- Commit messages, code comments, and public issue or PR text must not describe exploitable details of a security fix; present such changes as general hardening.
7388
74−Title Case rules (Chicago-style, with code- and path-aware normalization):
75−- Capitalize the first word, the first word after a colon, dash, or end punctuation, and all major words, including the second part of a hyphenated major word.
76−- Lowercase only articles, short conjunctions, and short prepositions of three letters or fewer when they are not in one of those positions.
77−- Preserve known acronyms (for example, API, CLI, HTTP, JSON) and slash-separated acronym groups (for example, CSV/TSV) as uppercase.
78−- Preserve RFC 2119 / RFC 8174 normative keywords (MUST, SHOULD, MAY, SHALL, REQUIRED, RECOMMENDED, OPTIONAL) as uppercase when used in their normative sense.
79−- Preserve inline code spans (`` `foo` ``), file paths (e.g. `docs/foo-bar.md`), and slash commands (e.g. `/grill-me`) verbatim; do not recase their contents.
80−- Use `&` instead of `And`/`Or` in headings.
89+## Performance & Reliability
8190
82−## Safety & Data
91+- Prefer using existing caches, workers, and batching strategies referenced in code and Makefile. Consider memory/CPU impact; suggest benchmarks or profiling only when justified.
8392
84−- If `git status` shows unexpected changes, assume a human may be editing; ask before using reset-style commands.
85−- Do not run `git config` at either the global or repository level.
86−- Do not run destructive commands against production data; prefer ephemeral volumes and test fixtures for acceptance tests.
87−- Never commit secrets, local configurations, or cache files; use environment variables or a local `.env`.
88−- Ensure `.env`, `.config`, `.local`, `.codex`, and `.gocache` are ignored in `.gitignore` and `.dockerignore`.
89−- Prefer existing caches, workers, and batching strategies already referenced by the code and `Makefile`.
90−- Consider CPU and memory impact; only suggest profiling or benchmarks when justified.
91−- If anything here conflicts with the `Makefile` or the sources of truth, ask for clarification before proceeding.
93+## When Unsure
9294
93−## Project Layout & Shared Rules
95+- Ask for the exact Makefile target or doc link you need, then proceed. Defer to SOT if any conflict arises.
9496
95−- Backend: Go in `internal/`, `pkg/`, and `cmd/`, backed by MariaDB or SQLite.
96−- Frontend: Vue 3 plus Vuetify 3 under `frontend/`.
97−- Local dev and CI use Docker Compose; Traefik provides local TLS via `*.localssl.dev`.
98−- Code in `pkg/*` must not import from `internal/*`. If you need config, entity, or DB access, add code under `internal/`.
99−- Shared Go rules:
100− - After Go edits, run `make fmt-go` and keep `gofmt` tab indentation.
101− - Every added/modified Go function, including unexported helpers, must have focused test coverage in the corresponding `*_test.go` files; update existing tests or add new ones as needed.
102− - Every Go package must contain a root `<package>.go` file with the standard license header and a short package description comment.
103− - Use `pkg/fs` permission constants: `fs.ModeDir`, `fs.ModeFile`, `fs.ModeConfigFile`, `fs.ModeSecretFile`, and `fs.ModeBackupFile`.
104− - When importing the stdlib `io/fs`, alias it to avoid collisions, for example `iofs "io/fs"` or `gofs "io/fs"`.
105− - Do not pass stdlib `io/fs` mode flags where permission bits are expected.
106− - Prefer `filepath.Join` for filesystem paths and `path.Join` only for URL paths.
107− - Normalize slash-based logical paths stored in DB, config, or API payloads with `clean.SlashPath(...)`.
108−- Shared JS/Vue rules:
109− - Added/modified JavaScript functions, including helpers, should be tested whenever practical; update existing tests or add new ones as needed.
110− - Added/modified Vue components should have component-test coverage, and existing component tests should be updated as needed when behavior changes.
111−- When adding a metadata source such as `SrcOllama` or `SrcOpenAI`, update both `internal/entity/src.go` and `frontend/src/common/util.js` so backend and UI stay aligned.
97+## References To Help Copilot Answer Questions
11298
113−### JS/Go Code Comments
99+- Show supported formats/filters: run `photoprism show file-formats` and `photoprism show search-filters` (use results rather than guessing).
100+- For CI/dev containers, assume a Linux/Unix shell on amd64 or arm64 by default; for Windows specifics, link https://docs.photoprism.app/developer-guide/faq/
114101
115−A doc comment is **required** for every function (including unexported helpers), as well as for every non-trivial Vue `methods:` / `computed:` / watcher:
116−- Keep comments **compact** and default to one line for "what" in the format `// Name does X.`. Skip trivial getters (`isOpen: () => this.open`).
117−- Add 1-2 follow-up lines (`// …`) **only** if the "why" is non-obvious: a hidden invariant, a workaround that would otherwise be undone by a future cleanup, a contract a reader can't infer from the code. If readers can infer the "why" from the function body or a nearby line, then omit it.
118−- Multi-paragraph explanations belong in `specs/`, package `README.md` files, or GitHub issues — never in the source itself.
102+## Output Expectations
119103
120−Doc comments for packages and exported identifiers must be complete sentences that begin with the name of the thing being described and end with a period. For short examples in comments, indent code instead of using backticks.
104+- Prefer short, actionable comments with code blocks that pass tests locally: `make test-js` (frontend) / `make test-go` (backend)
105+- If a suggestion requires additional context (e.g., DB access, external service), call it out explicitly.
121106
122−Use US English spelling in all code comments (`parameterized`, `behavior`, `color`, `serialize`, `normalize`, `optimize`, …) — not the British `-ised`/`-our`/`-re` variants.
107+## Safety Checklist Before Proposing a CLI Command
123108
124−> **Don't include in code comments:** Issue / PR numbers, "previously…" history, alternatives considered, what the function used to do, references to old commits, names of subsequent reviewers, or any narrative that names the change rather than the steady-state behavior. That context belongs in commit messages, specs, or handover notes.
125−
126−## Agent Runtime
127−
128−- Detect container mode by checking for `/.dockerenv`.
129−- If the repo path is `/go/src/github.com/photoprism/photoprism` and `/.dockerenv` is absent, treat the environment as host mode with a bind mount and prefer host-side Docker commands.
130−- Bash check: `[ -f "/.dockerenv" ] && echo container || echo host`
131−- Node.js check: `require("fs").existsSync("/.dockerenv")`
132−- Inside the container, prefer `npm exec --yes <agent> -- --help` or `npx <agent> ...`; if a global npm install is unavoidable, install it only inside the container.
133−- The `photoprism/develop` base image and the repo `Makefile` both set `NPM_CONFIG_IGNORE_SCRIPTS=true`, so `npm ci`/`npm install` via `make` targets skip install scripts out of the box. When running npm directly in an environment that does not set or inherit that default, pass `--ignore-scripts` explicitly to mitigate supply-chain attacks. Rebuild native addons with `npm rebuild --ignore-scripts=false <pkg>` — a bare `npm rebuild` is a silent no-op wherever the env default is active.
134−- On the host, use the vendor-recommended install method and run from the repository root so agent discovery sees this file.
135−
136−## Build, Format & Test
137−
138−- Run `make help` for an overview of the most common targets, and `make list` to see all of them.
139−- Host mode:
140− - `make docker-build`
141− - `docker compose up` or `docker compose up -d`
142− - `docker compose logs -f --tail=100 photoprism`
143− - `docker compose exec photoprism ./photoprism help`
144− - `docker compose exec -u "$(id -u):$(id -g)" photoprism <command>` to avoid root-owned files
145− - `make terminal`
146− - `docker compose --profile=all down --remove-orphans` or `make down`
147−- Container mode:
148− - `make dep`
149− - `make build-js` and `make build-go`
150− - `make watch-js` or `cd frontend && npm run watch`
151− - `./photoprism start`
152− - Local URLs: `http://localhost:2342/` and, with Traefik, `https://app.localssl.dev/`
153− - Local compose defaults to `admin` / `photoprism`; inspect `compose.yaml` if they differ.
154− - Do not use the Docker CLI inside the container; manage Compose from the host instead.
155−- The public CLI name is always `photoprism`; development-only side-by-side binaries may use edition-specific names.
156−- Our command examples assume a Linux or Unix shell on 64-bit AMD64 or ARM64; see the Developer Guide FAQ for Windows-specific notes.
157−
158−Formatting and test entry points:
159−- Full suite: `make test`, `make lint`
160−- After renaming or removing a Makefile target, run `make check-make-help` (also included in `make lint`) so that no `make help` overview keeps advertising it.
161−- Go-specific lint, format, and package-test rules live in [`internal/AGENTS.md`](internal/AGENTS.md).
162−- Frontend lint, Vitest, acceptance, and Playwright rules live in [`frontend/AGENTS.md`](frontend/AGENTS.md).
163−- Go tests live next to their sources; use PascalCase `t.Run(...)` names for related subtests. Keep consecutive subtests inside the same `Test*` function back-to-back without blank lines so the cases read as a compact table; reserve blank lines for separating distinct setup blocks.
164−- Do not run multiple test commands in parallel; suites share fixtures, assets, and database state.
165−- Prefer focused test runs such as `go test ./path/to/pkg -run Name -count=1` while iterating.
166−- Use `mariadb -D photoprism` inside the dev shell when you need to inspect MariaDB state directly.
167−- Run `shellcheck <file>` on edited shell scripts, or use the corresponding `make` target.
168−
169−### Continuous Integration
170−
171−- **GitHub Actions is not enabled for this repository.** The workflow files under `.github/workflows/` do not execute, so pushes and pull requests produce no check runs. Treat them as dormant configuration: do not diagnose the absence of runs as a broken workflow, do not propose enabling Actions, and do not add workflows or bot configuration that assumes they will run. Ask a maintainer before changing anything under `.github/workflows/`.
172−- The `make` targets above are the authoritative build, format, and test gate. Run them locally and report the output rather than relying on a hosted runner.
173−
174−### Container Image Builds
175−
176−- **Never mix Debian and Ubuntu `apt` repositories in the same image:**
177− - Don't add a Debian source to an Ubuntu base (or vice versa) to install a single missing package — the transitive deps drift, apt's solver pulls newer libraries from the foreign distro, and other build steps in the same `RUN` (e.g. `install-libheif.sh` running `apt-get install libavcodec-dev`) silently link against the wrong soname.
178− - Symptoms surface much later as `dlopen: libfoo.so.N: cannot open shared object file` at image runtime, with the binary referencing a soname that exists only in the foreign distro.
179− - If a package isn't available in the host distro's repos, prefer (a) a same-distro PPA / backports source, (b) a vendor-supplied .deb (e.g. Google Chrome from `dl.google.com`), or (c) a from-source build pinned to a known version.
109+- Include a dry-run or non-destructive variant if possible.
110+- Recommend creating/using backups before any reset/migrate.
180111
