Skip to content

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 (18).
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:

  1. Mount (global). Every event must match at least one mount.inclusions pattern (or the list is empty) and must not match any mount.exclusions pattern.
  2. 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.