The Telescope Net cloud server is a Flask API that sits at the centre of the whole network. It ingests alerts from half a dozen astronomical brokers every hour, scores every (target, node) pair, generates nightly observation plans for each connected Seestar, and batches accepted photometry to AAVSO WebObs — all with no manual intervention. This page walks you through running it locally in a few minutes.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ManiFed/TTN/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites
- Python 3.10 or later
pipavailable in your environment- Your AAVSO credentials (observer code, username, password)
- A PostgreSQL database URL (set as
DATABASE_URLin the environment — Railway and Fly.io provide this automatically) - Optional:
ANTHROPIC_API_KEYif you want to enable the nightly Claude weight-tuning monitor
Setup
The weight-tuning monitor is opt-in and ships disabled. If you want to turn it on later, install the Anthropic client now and export your key:
Open
cloud/config.yaml and fill in the three required fields before the server will accept live AAVSO submissions:server:
admin_key: '${CLOUD_ADMIN_KEY}' # change this — never commit the real value
aavso:
observer_code: 'MXXX' # your AAVSO OBSCODE
username: '${AAVSO_USERNAME}'
password: '${AAVSO_PASSWORD}'
The config expands
${VAR} references from the environment, so you can keep secrets out of the file entirely by exporting CLOUD_ADMIN_KEY, AAVSO_USERNAME, and AAVSO_PASSWORD in your shell.On Railway or Fly.io this variable is injected automatically. Locally, any PostgreSQL instance works — a fresh Homebrew install with
createdb telescopenet is sufficient for development.The server binds to
0.0.0.0:8800 by default. You should see log lines as the background loops start up.Background Loops
Once the server starts, four daemon threads begin running automatically. Each loop is independent — one failure never kills another.| Loop | Frequency | Description |
|---|---|---|
alert-ingest | Every 60 min | Poll ALeRCE, ATLAS, ASAS-SN, AAVSO, Gaia, and TNS for new transients and variable-star alerts; trigger rescoring when new targets appear |
replan | Every 120 min | Rescore every active target against every active node; regenerate CHORUS observation plans for the whole fleet |
aavso-batch | Every 360 min | Assemble accepted photometry measurements into AAVSO Extended File Format and submit to WebObs |
maintenance | Daily | Prune raw images older than the retention window, generate night summaries, refresh node performance metrics, and (if enabled) run the CHORUS T0 ledger update and the Claude weight-tuning monitor |
cloud/config.yaml under alerts.interval_minutes, scheduler.replan_interval_minutes, and aavso.batch_interval_minutes.
Database
The cloud server uses PostgreSQL accessed through a connection pool. On startup,db.init() creates the full schema if it does not exist, then runs all column migrations idempotently — so you can upgrade a running deployment by restarting without any manual ALTER TABLE steps.
Core tables: nodes, targets, scores, plans, measurements, aavso_batches, interrupts, tuning_state, weight_history, and the CHORUS-specific ledger tables (chorus_node_ledger, chorus_target_state, chorus_site_calibration, chorus_run_archive).
Seeding Demo Data
The server looks best with realistic node locations and a sample light curve. Run the seed script once after starting the server:Production Deployment
The repo ships ready-made deployment configs for two platforms:- Railway —
railway.tomlat the project root; one-command deploy via the Railway CLI - Fly.io —
fly.tomlat the project root;fly deploybuilds and launches the server
DATABASE_URL automatically. Set CLOUD_ADMIN_KEY, AAVSO_USERNAME, and AAVSO_PASSWORD as environment secrets in the platform dashboard before deploying.
For production use, the server is served through cloud/wsgi.py with gunicorn rather than the built-in Flask development server that python3 -m cloud.main starts.
CHORUS is the default live scheduler. The config key
scheduler.chorus: true is set out of the box, so every call to generate_all_plans delegates to the CHORUS information-theoretic coordinator described in CHORUS. To fall back to the legacy greedy packer at any time, set scheduler.chorus: false — no restart of background infrastructure is required.