control plane

Pulse

Service registry and shared configuration layer. Beacon apps register with it out of the box, and any Go service can join through the client SDK at pkg/sdk — tap into shared indexers, quality profiles, and settings with a single client instance.

Port :9696 Go 1.25 Postgres MIT

What Pulse does

Service registry

Each Beacon service registers on startup with its name, type, URL, and capabilities, then heartbeats periodically. Move Pilot to a new host — Prism picks up the address on the next heartbeat cycle with no config edits.

Indexer management

Add a Torznab endpoint once. Tag it movies and Prism picks it up. Tag it tv and Pilot gets it too. Built-in catalog with pre-filled schemas, one-click add, and a tester that verifies connectivity before saving.

Quality profile management

Quality profiles live in Pulse. Subscribing services mirror them with a managed_by_pulse flag. Edit a 1080p cutoff once in Pulse — both Pilot and Prism update without a config edit in either service.

Shared settings store

A typed key-value store for cross-service settings: media.library_root, rename.colon_replacement, download.preferred_protocol. Each service reads and subscribes to its relevant namespace.

WebSocket event stream

Services subscribe to live updates at /ws. When shared state changes, every subscriber is notified immediately — no polling required. The SDK callback fires synchronously on each event.

Go client SDK

A drop-in SDK at pkg/sdk for any Go service. Register, discover peers, read and subscribe to shared config, and pull assigned indexers — all with one client instance and WebSocket-backed callbacks.

Dashboard

React 19 + TypeScript UI embedded in the Go binary. No separate server to run.

Dashboard — service overview + indexer status
Indexer catalog — search, filter, one-click add
Shared config — namespace filtering + subscriptions

Advanced features

API surface

Full REST API (Huma v2 + Chi v5) under /api/v1/. OpenAPI docs at /api/docs. WebSocket event stream at /ws. Everything the UI does is available over HTTP.

SDK — register and subscribe

pkg/sdk
client, _ := sdk.New(sdk.Config{
    PulseURL: "http://pulse:9696",
    ServiceName: "pilot",
    Capabilities: []string{"supports_torrent"},
})
client.Subscribe(ctx, "media", func(ns, key, val string) {
    // fires on WebSocket events
})

Storage

Postgres-backed state with Goose migrations and SQLC-generated type-safe query code. Zero configuration out of the box — all settings editable in the UI or via PULSE_* environment variables.

Tag management

Central tag registry with usage counts. Tags drive indexer assignment (tv, movies, all), notification routing, and library filtering across every service — managed once in Pulse.

Getting started with Pulse

Standalone Docker for a single-service install. Full stack compose in beacon-stack/stack.

docker
docker run -d \
  --name pulse \
  -p 9696:9696 \
  -v /path/to/config:/config \
  ghcr.io/beacon-stack/pulse:latest

Open http://localhost:9696 — Pulse starts with zero additional configuration.

Environment variables

Variable Default Description
PULSE_SERVER_HOST0.0.0.0Bind address
PULSE_SERVER_PORT9696HTTP port
PULSE_DATABASE_DSNPostgres connection string
PULSE_AUTH_API_KEYauto-generatedAPI key for external access
PULSE_LOG_LEVELinfodebug, info, warn, error
PULSE_LOG_FORMATjsonjson or text