Development¶
How to work on Filearr locally: the repo layout, dev commands, tests, and contribution basics under the AGPL.
Repository layout¶
backend/filearr/
main.py FastAPI app factory (SPA static mount, /api/v1)
config.py pydantic-settings — every FILEARR_* env var
models.py SQLAlchemy 2.0 models (libraries, items, scans, agents, ...)
media_types.py extension -> media-type map
security.py Bearer API keys + scopes (read/write/admin)
rbac.py path-scoped RBAC (ltree grants)
search.py Meilisearch projection (build_doc, ensure_index, rebuild)
querydsl.py the saved-query / filter-builder grammar
agentsync.py the agent replication wire contract (central half)
worker.py Procrastinate app + periodic jobs (purge, reconcile, reap)
api/ search, items, libraries, scans (SSE), system, agents, ...
tasks/ scan (walk/diff/tombstone), extract (per-type), index_sync, thumbs, ...
backend/alembic/ migrations (baseline + revisions)
backend/tests/ pytest suite
frontend/src/ Svelte 5 SPA (App.svelte, lib/AdminPage.svelte, lib/api.ts)
agent/ the Go agent (cmd/filearr-agent, cmd/filearr-release, internal/*)
docker-compose.yml, Dockerfile, unraid/, proxmox/, scripts/
Dev commands¶
Backend (Python 3.14 via uv):
cd backend && uv sync
uv run uvicorn filearr.main:app --reload # API on :8000
uv run procrastinate --app=filearr.worker.proc_app worker # a worker
Frontend (Node ≥ 24):
cd frontend && npm install
npm run dev # Vite dev server, proxies /api to :8000
npm run build # production build (served from FastAPI static)
npm run check # svelte-check / typecheck
Agent (Go ≥ 1.26, no cgo):
cd agent
go build ./cmd/filearr-agent
go test ./...
# cross-compile:
GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build ./cmd/filearr-agent
Full stack via Docker:
The bootstrap is idempotent. API docs are at /api/docs. For a quick look with
auth off, set FILEARR_AUTH_ENABLED=false.
Tests¶
cd backend && uv run pytest # backend suite (pytest-asyncio)
cd agent && go test ./... # agent suite (incl. an in-process step-ca authority)
cd frontend && npm run check # frontend typecheck
The backend suite prefers an external Postgres 18 service — point
FILEARR_TEST_DATABASE_URL at it (an embedded Postgres fallback is used only on
older Python). Because some Postgres extension types (e.g. ltree) are only
present on a real Postgres, run tests against a real Postgres 18 to catch the
extension-type behaviors that a bare test database would miss.
Lint/format uses ruff:
Contribution basics (AGPL)¶
Filearr is licensed under AGPL-3.0-or-later. Contributions are accepted under
the same license with a DCO sign-off — add Signed-off-by: to your commits
(git commit -s).
Keep the architecture invariants intact — they are load-bearing:
- The search index is disposable (rebuildable from Postgres).
- Extracted
metadataanduser_metadataare separate columns; scans/extractors write only the former, API/UI edits only the latter. - Item identity is
(library, relative path). - Scans never hard-delete (tombstone + recycle-bin purge).
- Defer extract jobs only after the batch commit (workers race uncommitted rows otherwise).
- Media mounts are read-only.
- A crashed scan must mark its scan run
failed— never leave itrunning.
If you run a modified Filearr for others over a network, AGPL §13 requires you to
offer them the Corresponding Source — set FILEARR_SOURCE_URL to your fork.