Pilot
A self-hosted TV series manager with a React web UI and a REST API. Tracks your TV library via TMDB, polls indexers (the search APIs that catalog releases) for new episodes, hands grabs to your download client, and files completed downloads into season folders.
Features
What Pilot does
Library management
Full TMDB integration for search, metadata, posters, and episode tracking. Per-series monitoring with configurable monitor types. Season and episode-level monitoring controls, wanted page, and a calendar view of upcoming episodes.
Release handling
Quality profiles — ranked lists of acceptable resolutions, sources, codecs, and HDR variants — drive the grab decision. Custom formats with regex matching and weighted scoring layer on top. A title-match filter rejects releases whose parsed show name doesn't match the requested series, so a "The Office" search never grabs an "Office Space" pack with overlapping words.
Dead-torrent detection
The stallwatcher polls your download client for stalled torrents and blocklists them. A per-episode circuit breaker caps auto-blocklist events at three strikes per 24 hours so a misconfigured indexer can't trigger a retry storm.
Automation
Automatic RSS sync on a configurable schedule. Auto-import of completed downloads with rename support. Import lists from TMDB, Trakt, Plex Watchlist, and custom URL lists. Season folder organization with configurable naming.
Integrations
Indexers via Newznab and Torznab (the two standard search APIs the *arr ecosystem speaks), either configured locally or synced from Pulse. Download clients: Haul, qBittorrent, Deluge, Transmission, SABnzbd, NZBGet. Media servers: Plex, Jellyfin, Emby. Notifications: Discord, Slack, Telegram, Pushover, Gotify, ntfy, email, webhook, custom command.
Command palette
Cmd/Ctrl+K command palette with fuzzy search for pages, series, and actions. Eighteen theme presets (thirteen dark, five light) shared across every Beacon service. Live queue updates over WebSocket. OpenAPI docs at /api/docs.
Interface
Screenshots
React 19 + TypeScript UI embedded in the Go binary.
Technical
Advanced features
Title matching
The release filter runs every parsed title through a matcher in internal/core/parser/parser.go that rejects titles whose parsed show name doesn't match the requested series after normalization. Year suffixes, bracketed edition tags, and common release-group stylings all pass through cleanly.
Stallwatcher circuit breaker
internal/core/stallwatcher/service.go polls the download client's stall endpoint on a configurable interval, classifies stalled torrents by reason, and blocklists them. The per-episode circuit breaker caps auto-blocklist events at three strikes per 24 hours.
Interactive search ranking
Releases sort by Quality → Episode Count → age-aware log10 Seed Weight → Age. The Episode Count tier lifts season packs above individual episodes within the same quality tier, the way Sonarr's release comparer does. The Seed Weight tier — log10 of the seed count, with an age cap on torrents older than a year — is what stops the 847-seeder, five-year-old release with zero actual peers from winning the sort.
Sonarr migration
Pilot imports from a running Sonarr instance in one pass. Open Settings → Import, enter the Sonarr URL and API key, preview, and select categories. Supported: quality profiles, libraries, indexers, download clients, and monitored series.
docker run -d \ --name pilot \ -p 8383:8383 \ -v /path/to/config:/config \ -v /path/to/tv:/tv \ ghcr.io/beacon-stack/pilot:latest
Open http://localhost:8383 — Pilot generates an API key on first run. Find it in Settings → App Settings.
Configuration
Environment variables
| Variable | Default | Description |
|---|---|---|
TV_PATH | — | Required. Host path to your TV library. Bound into Pilot at /tv. Must be on the same filesystem as DOWNLOADS_PATH for hardlink imports. |
DOWNLOADS_PATH | — | Required. Host path to completed downloads. Shared across Pilot, Prism, and Haul. |
PILOT_PORT | 8383 | Host port for the web UI and API. Set in .env if 8383 is taken. |
PILOT_CONFIG_PATH | ./config/pilot | Where Pilot's config.yaml and cached state live. |
LOG_LEVEL | info | Set once in .env; Compose passes the same value to every Beacon service. debug, info, warn, error. |
TZ | UTC | IANA timezone (e.g. America/New_York). Set once in .env and applied to every service for log timestamps and scheduled tasks. |