A self-hostable framework for building trackers. Trackers (movies/TV, GitHub PRs, and eventually anything) are plugins over a shared core that provides storage, indexing, full-text search, sync scheduling, and per-user tracking state, all backed by a single Postgres database.
Requirements: Rust, Docker, Bun.
# one-time: env file (compose, the daemon, and sqlx tests all read it)
cp .env.example .env
# start Postgres only
docker compose up -d postgres
# build the web UI once (the daemon serves ui/dist)
cd ui && bun install && bun run build && cd ..
# run the daemon locally against it
cargo run --bin lapidaryThe daemon listens on :8480 (LAPIDARY_LISTEN overrides) and serves the web
UI at /. Health check at GET /healthz. Steel tracker plugins are loaded
from plugins/ (LAPIDARY_PLUGINS_DIR overrides).
Tests need a running Postgres (docker compose up -d postgres):
cargo test --workspaceThe full stack (daemon plus Postgres) runs from the compose file on any small VPS (4 GB RAM is plenty):
POSTGRES_PASSWORD=change-me docker compose --profile full up -dTracking state is the only backup-critical data; catalog data can always be
re-imported by plugins. A pg_dump of the entity_state, entity_tags, and
users tables is a complete backup.
Open http://localhost:8480, go to settings, add a tracker instance (the config form is generated from the plugin's manifest; secret fields can be left blank later to keep their stored values), and hit "Sync now". The same works over the API:
# movies (Rust plugin, needs a TMDB API key)
curl -X POST localhost:8480/api/instances -H 'content-type: application/json' \
-d '{"plugin_id":"movies","name":"my-movies","config":{"api_key":"<tmdb-key>","pages":2}}'
# github PRs (Steel plugin from plugins/github.scm)
curl -X POST localhost:8480/api/instances -H 'content-type: application/json' \
-d '{"plugin_id":"github","name":"my-prs","config":{"token":"<gh-token>","repos":["you/repo"]}}'
# trigger a sync now (also runs on a schedule), then browse http://localhost:8480
curl -X POST localhost:8480/api/instances/<id>/sync
curl localhost:8480/api/instances/<id>/runsThe movies plugin accepts a lists config (popular, top_rated, trending,
now_playing; default popular). Anything not on the lists can be imported on
demand: search inside the tracker in the UI and use "Search the source", or
via the API:
curl "localhost:8480/api/instances/<id>/lookup?q=the+matrix"
curl -X POST localhost:8480/api/instances/<id>/import \
-H 'content-type: application/json' -d '{"reference":"movie:603"}'On-demand imports are pinned: catalog sweeps never remove them.
crates/core: storage, indexing, search, sync engine, tracking statecrates/plugin-api: the plugin contract (manifest types, ctx API)crates/daemon: axum HTTP API, scheduler, web UI hostcrates/plugins/movies: movies/TV tracker (Rust, TMDB)plugins/: Steel tracker definitions (GitHub tracker)