README.md was last touched in 4aff9c5 (2026-05-14) and several of its
most visible lines had gone false:
- "Pre-v1. Not yet functional." — FC has been continuously deployed for
months. Replaced with what main/dev actually mean for what's running.
- "Node 22 pre-installed" — ci-requirements.md and extension.yml both say
node 24, and frontend/package.json requires >=24.
- "Runner label python-ci — a runner with Python 3.14, ruff and Node 22
pre-installed ... The runner image (runner-base:python-ci) is built
from CI-Runner/CI-python/" — describes runs-on as selecting the
toolchain. It doesn't: runs-on is a scheduling label, and every job
names its own container.image (ci-python:3.14, or node:24-bookworm-slim
for the extension lane).
- "Both ci.yml and build.yml use this label" — there are three workflows.
The CI section now points at ci-requirements.md rather than restating
it, so the two can't drift apart again; that file is current and is the
one the CI-runner process expects.
Added a "What's in here" table for the five deployable pieces — the
extension, the GPU agent and the ML image were unmentioned, three of the
five. Also corrected the RELEASE_TOKEN write:release scope, which is no
longer "for future release-cutting workflows": it backs the ext-<version>
releases that cache the signed XPI.
Refs #3070
80 lines
4.0 KiB
Markdown
80 lines
4.0 KiB
Markdown
# FabledCurator
|
|
|
|
Self-hosted media curation — gallery, ML tagging, and subscription-driven downloading in one app. Part of the FabledSword family.
|
|
|
|
Combines what was [ImageRepo](https://git.fabledsword.com/bvandeusen/ImageRepo) (gallery, ML, importer) and [GallerySubscriber](https://git.fabledsword.com/bvandeusen/GallerySubscriber) (gallery-dl wrapper, subscriptions, credential capture) into a single product.
|
|
|
|
## Status
|
|
|
|
In production. `main` is continuously deployed — every merge to `main` builds
|
|
and publishes `:latest` images, so whatever is on `main` is what is running.
|
|
Day-to-day work happens on `dev`, which publishes `:dev` images.
|
|
|
|
## What's in here
|
|
|
|
Five deployable pieces, built by `.forgejo/workflows/build.yml`:
|
|
|
|
| Piece | Built from | Image | Role |
|
|
| --- | --- | --- | --- |
|
|
| **Web / workers** | `Dockerfile` | `fabledcurator` | Quart API + the built Vue SPA in one image. `entrypoint.sh` picks the role: `web`, `worker`, `scheduler`. The `maintenance-long` service is a second `worker` pinned to the long-running maintenance queue. |
|
|
| **ML worker** | `Dockerfile.ml` | `fabledcurator-ml` | Same app, plus `requirements-ml.txt` — tagging and embedding models that run in-container. |
|
|
| **GPU agent** | `agent/Dockerfile` | `fabledcurator-agent` | Optional desktop-GPU worker (`agent/`). Leases jobs over **HTTP only** — never touches the database or Redis. Run it for a burst, stop it to reclaim the card. See `agent/README.md`. |
|
|
| **Firefox extension** | `extension/` | signed XPI | MV3 extension: pushes platform session cookies into FC and adds a creator as a Source in one click. AMO-signed on `main` only, then bundled into the web image and served from Settings → Maintenance. See `extension/README.md`. |
|
|
| **Data** | — | `pgvector/pgvector:pg16`, `redis:7-alpine` | Postgres with pgvector for embeddings; Redis as the Celery broker. |
|
|
|
|
## Quick start
|
|
|
|
For local development and testing, just:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
# UI: http://localhost:8080
|
|
```
|
|
|
|
That uses sane dev defaults baked into `docker-compose.yml` and the dev
|
|
override (`docker-compose.override.yml`, auto-merged) — local builds, DEBUG
|
|
logging, exposed Postgres + Redis ports on the host. No `.env` required.
|
|
|
|
For a production-like deployment, override the dev defaults via shell env
|
|
or a `.env` file (see `.env.example` for the variable names) and use:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.yml up -d
|
|
# (skips the override so containers pull registry images)
|
|
```
|
|
|
|
The GPU agent is deployed separately, on the machine with the card —
|
|
`agent/docker-compose.yml`, not this stack.
|
|
|
|
## Deployment posture
|
|
|
|
FabledCurator is designed to run inside a self-hosted homelab environment over plain HTTP. If you want TLS, terminate it at your reverse proxy. The app does not generate certificates, redirect to HTTPS, or set HSTS.
|
|
|
|
## CI / Forgejo setup
|
|
|
|
Three workflows: `ci.yml` (lint, extension-version guard, backend unit tests,
|
|
frontend build, integration), `extension.yml` (extension lint, vitest, XPI
|
|
content verification), and `build.yml` (sign + publish).
|
|
|
|
**The toolchain each job runs in is its `container.image`, not its `runs-on`
|
|
label.** `runs-on: python-ci` only schedules the job onto a runner; every job
|
|
then names the image it actually wants. `ci-requirements.md` is the current,
|
|
authoritative list of images and per-job installs — read that rather than a
|
|
copy here, so the two can't drift.
|
|
|
|
The repo expects one secret:
|
|
|
|
- **`RELEASE_TOKEN`** — a Forgejo PAT with:
|
|
- `write:package` + `read:package` — for `docker push` to `git.fabledsword.com`
|
|
- `write:release` — for the `ext-<version>` releases that cache the signed XPI
|
|
- `write:issue` — for issue-management automation
|
|
|
|
Generate at https://git.fabledsword.com/user/settings/applications. The injected `GITHUB_TOKEN` cannot be used because it lacks `write:package`.
|
|
|
|
AMO signing additionally needs `MOZILLA_AMO_JWT_KEY` / `MOZILLA_AMO_JWT_SECRET`; it runs on
|
|
`main` only and is cached per version, since AMO rejects a re-signed version.
|
|
|
|
## License
|
|
|
|
Personal project; use at your own discretion.
|