ZenLocalPoller configuration reference¶
ZenLocalPoller is the companion tool that subscribes to the ZenDRIVE MQTT
stream and reacts the moment media is created or deleted — refreshing your
rclone VFS cache so new files appear in your mount instantly, and (optionally)
triggering your media servers to scan just the changed paths.
This page is the complete reference for its config.yml. For the bigger picture
of the event stream see How live updates work; for a quick
walk-through see Setting up ZenLocalPoller.
Where do I get the binary and my MQTT credentials?
ZenLocalPoller ships as a single static Linux binary (no dependencies).
Download the current release (v0.1.0) from the
releases page.
Your MQTT username/password are issued when you sign up for the live-updates
(MQTT) product — check your welcome email or
open a support ticket.
How it reads configuration¶
The binary always reads config.yml from its current working directory —
there is no -config flag. Run it from the directory that holds your
config.yml:
./zenlocalpoller # reads ./config.yml from the working directory
Run it under a process supervisor (systemd, a container, etc.) so it stays
connected and keeps your view in sync. It emits systemd readiness/status
notifications (sd_notify), so a Type=notify unit shows live counters in
systemctl status.
Command-line flags¶
| Flag | Purpose |
|---|---|
-mqtt <id> |
Override mosquitto.client_id from the config (handy for running a second instance). |
-reset-process-time |
One-shot recovery: reschedule every queued event to fire at the minimum delay from now, instead of its original (possibly far-future) time. |
Minimal configuration¶
The smallest useful config connects to the broker and refreshes an rclone
mount:
mosquitto:
broker: mqtt.clearstreamer.com
port: "443"
client_id: my-unique-poller-id # must be unique per instance
username: your-mqtt-username # issued with your service
password: your-mqtt-password
mount:
path: /mnt/unionfs/ # your local mount base — always end with /
rclone:
enabled: true
host: 127.0.0.1
port: 5572 # rclone's default RC port — must match the mount's --rc-addr
remote: zenstorage # your rclone remote name (case-sensitive)
Pick a unique client ID
Each poller instance must use its own client_id. Two clients sharing an ID
will repeatedly disconnect each other from the broker.
Sections¶
Every section below is optional unless marked required. Omitted settings fall back to the defaults shown.
mosquitto — MQTT broker (required)¶
Connects to the ZenDRIVE event broker. The connection is always made over
WSS (WebSocket Secure / TLS), so port 443 is normal.
| Key | Default | Notes |
|---|---|---|
broker |
(required) | Broker hostname, e.g. mqtt.clearstreamer.com. |
port |
(required) | Quoted string, e.g. "443". |
client_id |
(required) | Unique ID for this instance. |
username / password |
(see note) | The credentials issued with your service. If omitted, a legacy built-in credential is used for backwards compatibility — always set your own. |
topic |
s3 |
Subscription topic. A /# wildcard is appended automatically. |
qos |
2 |
MQTT QoS level: 0, 1, or 2. |
keep_alive |
30s |
Keep-alive interval. |
connect_timeout |
60s |
Initial connection timeout. |
clean_session |
false |
If true, the broker discards previous session state on connect. |
tls.enabled |
false |
Optional. The transport is already TLS (WSS); enable this only to attach a custom TLS config. |
tls.skip_verify |
false |
Skip certificate verification — testing only. |
tls.ca_cert |
— | Path to a custom CA certificate (PEM). |
mosquitto:
broker: mqtt.clearstreamer.com
port: "443"
client_id: living-room-poller
username: your-mqtt-username
password: your-mqtt-password
topic: s3
qos: 2
mount — mount path & global filters (required)¶
Defines the local filesystem base that incoming event paths are translated to, plus the first (global) filter layer.
| Key | Default | Notes |
|---|---|---|
path |
(required) | Local mount base. Always terminate with /. |
inclusions |
(empty = all) | Only process events matching these patterns. |
exclusions |
— | Skip events matching these patterns. Exclusions always win. |
extension_exclusions |
— | Deprecated. Use **/*.ext glob patterns in exclusions instead. |
mount:
path: /mnt/unionfs/
inclusions:
- /mnt/unionfs/movies/
- /mnt/unionfs/television/
exclusions:
- /mnt/unionfs/games/
- "**/{.recyclebin,.downloads,.inbound}/**"
- "**/*.nfo"
- "**/*.jpg"
rclone — VFS cache invalidation¶
When enabled, the poller calls your rclone remote-control endpoint
(/vfs/refresh) so new files show up in the mount immediately.
| Key | Default | Notes |
|---|---|---|
enabled |
false |
Turn rclone cache refresh on. |
host |
127.0.0.1 |
Host of the rclone RC server. |
port |
5572 |
Port of the rclone RC server (rclone's default). Must match the mount's --rc-addr port. |
remote |
— | Your rclone remote name (case-sensitive). |
autoscan / autoscan-servers — media-server triggers¶
Optionally notify autoscan-capable servers (Sonarr, Radarr, Lidarr, …) to scan
just the changed paths. Use a single autoscan: block or an
autoscan-servers: list — not both. Each server applies its own filters,
the second filter layer, after the global mount filters.
| Key | Notes |
|---|---|
host / port |
Autoscan server address. |
username / password |
Autoscan credentials. |
inclusions / exclusions |
Per-server path filters (same rules as mount). |
triggers |
List of { path, trigger } mapping a path prefix to a named trigger endpoint. |
autoscan-servers:
- host: 127.0.0.1
port: 3030
username: foo
password: change-me
inclusions:
- /mnt/unionfs/television/
exclusions:
- /mnt/unionfs/television-int/
triggers:
- path: /mnt/unionfs/tv/90s/
trigger: sonarr90s
poller — timing & retries¶
| Key | Default | Notes |
|---|---|---|
delay |
30s |
Minimum wait before an event is processed (lets file operations settle). Minimum 30s. |
poll-interval |
30s |
How often the queue is checked for due events. |
retries |
5 |
Max retry attempts before an event is dropped (exponential backoff). |
maintenance-window |
— | UTC window HH:MM-HH:MM; events arriving inside it are held until it ends. |
stats-interval |
15m |
How often stats are logged / pushed to systemd STATUS=. Set 0s to disable. |
paths — path translation¶
Incoming events use ZenDRIVE storage paths; feeder_paths rewrites them to your
local mount layout. Mappings apply sequentially — each mapping's output
feeds the next.
If omitted, two default mappings are generated, both pointing at mount.path:
/media/zen-ceph/ and /mnt/sharedrives/zd-storage-ceph-books/.
paths:
feeder_paths:
- source: /media/zen-ceph/
target: /mnt/unionfs/
- source: /mnt/sharedrives/zd-storage-ceph-books/
target: /mnt/books/
database — event persistence¶
A local SQLite database tracks pending events and history (used for retries and deduplication).
| Key | Default | Notes |
|---|---|---|
path |
zenlocalpoller.db |
SQLite file location. |
retention |
72h |
How long event history is kept before automatic purge. |
log — logging¶
Console (stderr) always gets colored, human-readable output. File output (when set) gets the same format without colors and is rotated.
| Key | Default | Notes |
|---|---|---|
level |
info |
trace, debug, info, warn, error, or fatal. |
file |
— | Optional log file path. The parent directory must exist; the file is created automatically. |
max-size |
5 |
Megabytes before rotation. |
max-age |
14 |
Days to retain rotated files. |
max-backups |
5 |
Number of rotated files to keep. |
anchors — mount-health gating¶
A list of files or directories that must exist before any event is processed. If any anchor is missing, processing pauses and events stay queued — useful for detecting when a remote mount goes offline. Transitions are logged once (available ↔ unavailable), not on every poll.
anchors:
- /mnt/unionfs/.downloads # hidden dir mounts expose when online
- /mnt/books/.mounted # a sentinel file placed at provisioning time
http — diagnostic server (optional)¶
Exposes a small HTTP server for health and tracker introspection.
| Endpoint | Method | Purpose |
|---|---|---|
/health |
GET | Connection / anchor status as JSON. |
/tracker/status |
GET | Per-bucket source coverage (only when monitor is enabled). |
/tracker/reset |
POST | Reset tracker counters. |
http:
address: 127.0.0.1:9090 # localhost only (recommended); use ":9090" to bind all interfaces
monitor / tracker — CephFS filesystem monitor (advanced)¶
Operator feature
The monitor is a secondary detection signal for operators who have a CephFS
filesystem mounted locally (e.g. on a dedicated CDN node). It polls
ceph.dir.rctime extended attributes to catch changes independently of MQTT.
Most S3-access customers do not need this — MQTT alone keeps an rclone
mount in sync.
When enabled, both sources feed the same queue and overlapping detections for a path are merged.
| Key | Default | Notes |
|---|---|---|
monitor.enabled |
false |
Enable the CephFS monitor. |
monitor.scan-interval |
10m |
Time between scans. Minimum 5m. |
monitor.workers |
4 |
Parallel scan workers (1–8). |
monitor.movie-flat-paths |
— | Depth 1 — children are movie directories. |
monitor.tv-flat-paths |
— | Depth 2 — children are shows; drills to season dirs. |
monitor.movie-nested-paths |
— | Depth 2 — children are language dirs, then movie dirs. |
monitor.tv-nested-paths |
— | Depth 3 — language → show → season. |
tracker.staleness-threshold |
3 × scan-interval |
When a source is considered stale. Only active with the monitor. |
Monitor paths are translated through the same paths.feeder_paths mappings, so
add a source/target entry covering each watch root.
How filtering works¶
Events pass through two filter layers before any action is taken:
- Mount (global). Every event must match at least one
mount.inclusionspattern (or the list is empty) and must not match anymount.exclusionspattern. - Per-autoscan-server. Each server then re-checks the event against its own
inclusions/exclusions.
In both layers exclusions win — if a path matches both an inclusion and an exclusion, it is excluded. An empty inclusion list means "include everything".
Pattern syntax¶
| Pattern | Matches |
|---|---|
/path/to/dir/ |
Plain prefix — auto-expands to /path/to/dir/** (note the trailing slash). |
/path/**/subdir/** |
** = zero or more directory levels. |
/path/**/{.a,.b}/** |
Brace alternation. |
**/*.ext |
Extension glob at any depth. |
/path/movies*/** |
* = wildcard within a single path segment. |
Trailing slashes matter
A plain path must end with / to auto-expand into a recursive match.
/mnt/unionfs/movies (no slash) is treated as a literal glob and will not
match files underneath that directory.
The binary bundles a sample.yml with the full annotated reference, and the
source tree includes a filtercheck helper for testing patterns before
deploying.
AI-assisted setup¶
Configuring config.yml for your exact mount layout and media servers is a
great task to hand to an AI assistant (Claude Code, Codex, etc.). Point it at
this page's URL and paste the prompt below. Fill in the bracketed details
first.
Pointable URL
https://wiki.clearstreamer.com/updates/configuration/
You are configuring `config.yml` for **ZenLocalPoller**, a tool that subscribes
to an MQTT stream and refreshes an rclone VFS mount (and optionally triggers
Sonarr/Radarr/Lidarr autoscan) when media is created or deleted.
Read the configuration reference at:
https://wiki.clearstreamer.com/updates/configuration/
Then generate a complete, valid `config.yml` for my environment:
- MQTT broker: mqtt.clearstreamer.com, port "443" (WSS).
- MQTT username / password: [paste the credentials issued with your service]
- A unique client_id for this machine: [e.g. living-room-poller]
- Local mount base path (must end with /): [e.g. /mnt/unionfs/]
- rclone remote-control host:port and remote name: [e.g. 127.0.0.1:5572, remote "zenstorage"]
- Media servers to trigger (host, port, credentials), or "none": [...]
- Content I want included / excluded: [e.g. include movies + television, exclude **/*.nfo, **/*.jpg]
Rules you must follow:
- Only use keys documented on the reference page; do not invent settings.
- Never fabricate MQTT or autoscan credentials — leave placeholders if I didn't provide them.
- client_id must be unique; never reuse one across machines.
- All plain directory patterns must end with `/` so they expand recursively.
- Keep defaults unless I asked to change them, and add a brief comment on each
non-obvious setting.
- Leave the CephFS `monitor` section out unless I explicitly run a local CephFS mount.
Always review the generated file before running it — in particular, confirm the
client_id is unique and the mount.path and rclone.remote match your
machine.