Applies to: any Linux host beside Frigate / optional for Elsinore
The Marcellus sidecar
On this page
Marcellus is an optional companion server you run next to Frigate. It is what turns Elsinore from a viewer into something that can tell you things.
What it adds
Elsinore works against a bare Frigate server: Live, Scrub, and the search feed all come from Frigate itself. Marcellus adds:
- Push notifications, Live Activities, and the attention ladder. Frigate has no Apple Push integration, so all of Alerts is sidecar-only.
- Scrub previews. A cache of rendered frames is what makes the reel fluid instead of a series of spinners.
- Encounters, and the Investigate and Follow views built on them.
- Deeper search, the structured stage below the app's instant client-side search.
- Face enrichment, which is where the recognised names that appear on event rows come from.
It reads Frigate's config, database, and recordings. It never writes to them.
Where it runs
Any Linux host that can see your Frigate install. In practice that is the same machine Frigate runs on, or a container beside it.
- Docker is the normal route: one container from
ghcr.io/helicopterrun/marcellus, on host networking, bind-mounting Frigate's config file, database directory, and recordings tree read-only. - A Python virtual environment with a systemd unit is the fallback where Docker is not available, which in practice means unprivileged LXC containers.
It needs to reach Frigate's two origins (the unauthenticated port, usually 5000, and the authenticated one, usually 8971) and your MQTT broker. The scrub cache additionally needs ffmpeg, which the Docker image already carries.
Installing it
The short version. The full instructions, including upgrades, live in the repository's deployment document.
- Run the installer, which detects Docker and falls back to the virtual
environment plus systemd unit. Or do it by hand:
docker composewith the published image, orpython3 -m venv /opt/marcellus/venv && pip install marcellus. - Generate a config with
fsc init, and pointfrigate.base_urlat Frigate's unauthenticated port andfrigate.proxy_base_urlat its authenticated one. Set the database, media, and recordings paths. - Make sure the service user can read Frigate's config, database, and recordings. Group membership or file ACLs, whichever suits your setup.
- Start the service and check
/healthz. Every component should be green, and MQTT in particular should read connected. - Open the web interface and confirm the Status page is serving.
Getting frigate.proxy_base_url wrong is the classic mistake, and it shows
up as repeated sign-in failures in the app. See
troubleshooting.
Pointing the app at it
Put the sidecar's address into Elsinore's Server step, not Frigate's, along with your Frigate username and password. The app talks to Frigate through the sidecar, so one address covers everything.
If you already set the app up against Frigate directly, change the URL in Settings › Server and save. Nothing else needs to move.
The operator manual
Marcellus serves its own documentation at /guide on the sidecar, which is
the real manual for running it. On Mac you can open it from Help › Guide
in the sidebar of Elsinore, already signed in. Its topics:
Welcome · First run · Elsinore setup · Elsinore app tour ·
Widgets and Live Activities · Push notifications · Status and live view ·
Scrub · Triage · Map and calibration · Motion and zone analysis ·
Tuning detection thresholds · Event search · Observations · Encounters ·
Face captures · Identities · Replay · Settings ·
Camera and detector health · fsc CLI reference · Deployment and upgrades ·
Troubleshooting
Some of those describe the sidecar's own web pages rather than the app. Triage and Identities in particular are web-only; the app displays the names identity work produces but does not manage them.
Encounters and topology
Encounters is a read-only layer over Frigate's review data that groups related detections into one human-describable story, for example a raccoon working its way from the alley to the shed. It chains each camera's bundled concurrent objects across cameras and time gaps using identity matches, shared zones, camera adjacency, and time-overlap, attaching a confidence and a stated reason to each link. Camera topology, meaning which cameras are next to which and how long a subject typically takes between them, is partly derived from your zone naming, partly learned from the transitions it sees, and correctable by hand, which is what makes the Same and Not same corrections in the app worth the swipe.