Skip to main content

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.

All cloud server behaviour is controlled by a single file: cloud/config.yaml. The server reads it at startup through load_config(), which recursively expands ${VAR} references from the environment — so secrets never need to be committed to the file itself. This page documents every section and parameter.
server.admin_key must be changed from the default placeholder before any production deployment. The admin key protects endpoints that can trigger ingestion, regenerate plans, and modify scoring weights. Set it via the CLOUD_ADMIN_KEY environment variable.

server

Controls the Flask API binding and authentication.
server:
  host: 0.0.0.0
  port: 8800
  admin_key: '${CLOUD_ADMIN_KEY}'
ParameterDefaultDescription
host0.0.0.0Interface the Flask server binds to. 0.0.0.0 makes the API publicly reachable — restrict to 127.0.0.1 for local-only access
port8800TCP port. The PORT environment variable overrides this, which Railway and Fly.io set automatically
admin_key(required)Secret header value for X-Admin-Key — authenticates admin API routes such as /api/v1/admin/ingest and /api/v1/admin/replan

aavso

Credentials and submission behaviour for AAVSO WebObs.
aavso:
  observer_code: 'EGBA'
  username: '${AAVSO_USERNAME}'
  password: '${AAVSO_PASSWORD}'
  chart_id: ''
  dry_run: false
  batch_interval_minutes: 360
  single_node_holdback_hours: 6
  audit_dir: cloud_data/aavso_batches
ParameterDescription
observer_codeYour AAVSO OBSCODE — appears in every submitted observation record
username / passwordAAVSO login credentials used to authenticate against WebObs
chart_idOptional AAVSO chart identifier; leave blank to omit from submissions
dry_runWhen true, the batch assembler formats the Extended File Format output but does not POST to WebObs — useful for verifying formatting before a live submission
batch_interval_minutesHow often (in minutes) the aavso-batch background loop runs; default 360 (every 6 hours)
single_node_holdback_hoursA measurement from a single node is held back this many hours to allow cross-validation against other nodes before submission
audit_dirDirectory where batch files are written before and after submission

database

database:
  url: 'postgresql://user@host/dbname'
The url value falls back to the DATABASE_URL environment variable if blank, which is how Railway and Fly.io inject it automatically. The full PostgreSQL connection string (including credentials) should be supplied via the environment rather than committed to the file.

alerts

alerts:
  interval_minutes: 60
  expire_days: 45
  alerce:
    enabled: true
    mag_limit: 16.0
    days_back: 14
  gaia:
    enabled: true
    mag_limit: 16.0
    days_back: 30
  tns:
    enabled: true
    api_key: ''
    bot_id: ''
    bot_name: ''
    mag_limit: 16.5
    days_back: 7
  atlas:
    enabled: true
    mag_limit: 16.5
    username: ''
    password: ''
  asassn:
    enabled: true
    mag_limit: 16.5
    api_key: ''
  aavso:
    enabled: true
    default_watchlist: true
    vsx_names: []
  tess:
    enabled: true
    mag_limit: 12.0
    min_depth_ppt: 5.0
    max_duration_hours: 4.0
interval_minutes controls how often the alert-ingest loop fires. expire_days deactivates transients that have not been seen by any source within that window. Each broker section has enabled, a mag_limit that caps how faint the ingested targets can be, and days_back controlling the historical lookback on each poll. TNS, ATLAS, and ASAS-SN require separate credentials — sources with blank credentials are skipped automatically without error. The tess section ingests upcoming TESS transit events. mag_limit caps the host-star V magnitude (Seestar S50 photometry requires V ≤ 12); min_depth_ppt filters out transits shallower than this threshold; max_duration_hours skips transits longer than 4 hours that cannot fit within a single night.

scoring

The scoring section contains two sets of weights: the composite weights that blend six target-level factors into a single score, and the observability sub-weights that are blended into the observe component of that composite.

Composite weights

scoring:
  weights:
    brightness: 0.20
    science:    0.25
    time:       0.15
    coverage:   0.15
    observe:    0.25
    roi:        0.10
WeightRole
brightnessHow well the target’s magnitude falls within the node’s dynamic range
scienceTarget priority set by the alert source or campaign programme
timeUrgency — fresh transients score high on day 0 and decay over ~12 days
coverageBlends short-term recency (40 %) with long-term historical neglect weighted by science priority (60 %)
observeComposite observability score (see sub-weights below)
roiScience yield: blends AAVSO acceptance rate, cadence-gap closure, and time-critical success over the last 90 days

Observability sub-weights

scoring:
  observability_weights:
    light_pollution: 0.20
    weather:         0.25
    moon:            0.15
    airmass:         0.15
    window:          0.15
    telescope:       0.10
These weights are seed values only. The live values are stored in the tuning_state database table and read fresh on every scoring run via tuning.active_obs_weights(). When the Claude weight-tuning monitor is enabled, it can adjust these values nightly within the trust-region bounds described in the tuning section.
Sub-weightRole
light_pollutionSky brightness penalty scaled to target magnitude — bright targets tolerate light pollution; faint ones require dark skies (mpsas 22 = pristine, 17 = inner city)
weatherComposite night-level weather score blending cloud cover, seeing, and atmospheric transparency from 7timer ASTRO and Open-Meteo forecasts
moonPenalty for lunar interference — scales with illumination and angular separation between the moon and the target at midnight
airmassAtmospheric extinction penalty — best airmass X=1 scores 1.0; X=3 scores 0
windowFraction of the dark window the target is above the node’s minimum altitude — at least 4 hours visible scores 1.0
telescopeHardware suitability: aperture-limited magnitude headroom, field-of-view match to the target class

Slot-quality weights

scoring:
  slot_quality_weights:
    altitude:       0.35
    cloud:          0.20
    seeing:         0.15
    transparency:   0.10
    moon:           0.10
    sky_brightness: 0.05
    thermal:        0.05
These weights control the time-resolved within-night placement of an observation — how much each per-slot factor influences which slot a given observation is assigned to. Like the observability sub-weights, these are seed values only and are live-tuned in the tuning_state table.
Sub-weightRole
altitudeHow high the target rides at this slot — airmass / atmospheric extinction
cloudPer-slot clear-sky fraction
seeingPer-slot atmospheric steadiness
transparencyPer-slot extinction
moonPer-slot moon separation × illumination
sky_brightnessPer-slot sky background level
thermalUncooled-camera penalty on faint targets at warm slots

tuning

The nightly weight-tuning monitor reviews observation outcomes and proposes small adjustments to the scoring weights. It ships disabled and is entirely opt-in.
tuning:
  enabled: false
  api_key: ''
  model: claude-opus-4-8
  lookback_nights: 14
  max_delta: 0.05
  max_delta_coord: 0.15
  min_nights_data: 7
  min_measurements: 30
  min_change: 0.005
ParameterDescription
enabledSet true to activate the nightly Claude advisory monitor. Defaults to false — behavior is identical to static weights when disabled
api_keyAnthropic API key. Leave blank to fall back to the ANTHROPIC_API_KEY environment variable
modelClaude model used for weight proposals. claude-opus-4-8 by default; set claude-sonnet-4-6 to reduce cost
lookback_nightsHow many nights of observation outcomes the monitor analyses per run
max_deltaTrust-region clamp — no single weight in any normalized group can move more than this per night (0.05 = ±5 %)
max_delta_coordFractional step cap for scalar coordination knobs and CHORUS hyperparameters (0.15 = ±15 % of current value)
min_nights_dataTuning is skipped until at least this many nights of data exist
min_measurementsTuning is skipped until at least this many measurements have been recorded
min_changeIf no weight in any group moves more than this amount, the run is considered a no-op and no audit row is written
The ANTHROPIC_API_KEY environment variable must be set (or tuning.api_key filled in) for the monitor to make any Claude calls. If no key is found, the tuning step silently skips and all weights remain unchanged. The hot path — alert ingestion, composite scoring, and CHORUS plan generation — never calls Claude regardless of this setting.

scheduler

scheduler:
  chorus: true
  chorus_shadow: false
  network_optimizer: false
  local_search_ms: 1500
  replan_interval_minutes: 120
  min_score: 0.25
  max_targets_per_night: 12
  sun_altitude_limit: -12
ParameterDescription
chorustrue enables CHORUS as the live scheduler (default). Set false for instant rollback to the legacy path
chorus_shadowRuns the full CHORUS pipeline alongside the incumbent, recording telemetry and backtest archive without saving plans — the staged rollout path
network_optimizertrue enables the previous marginal-value fleet optimizer; only effective when chorus: false. Defaults to false
local_search_msBudget in milliseconds for the seeded deterministic local-search refinement after the greedy assignment pass
replan_interval_minutesHow often the replan loop fires
min_scoreTargets scoring below this threshold are never scheduled
max_targets_per_nightHard cap on the number of distinct targets per node per night
sun_altitude_limitSun altitude in degrees defining the start and end of the observing window (−12 = nautical darkness)

Coordination knobs

scheduler:
  coordination:
    redundancy_decay: 0.55
    redundancy_diversity_sep: 90.0
    cadence_bonus_strength: 1.0
    slew_cost_weight: 1.0
    slew_deg_per_s: 3.0
    slew_settle_s: 15.0
    filter_change_cost_s: 60.0
    meridian_flip_cost_s: 120.0
    preferred_target_boost: 0.10
    robustness_cloud_relax: 0.20
    slot_quality_floor: 0.50
    local_search_aggressiveness: 1.0
These are seed values only — live values are stored in tuning_state and adjusted by the nightly weight-tuning monitor. All keys are bounded and clamped per run.
KnobDescription
redundancy_decayValue retained per extra network observation of the same target (lower = punish redundant coverage harder)
redundancy_diversity_sepLongitude separation in degrees for full geographic diversity credit
cadence_bonus_strengthHow strongly the scheduler spreads samples across time gaps (0 = ignore cadence, 1 = full shaping)
slew_cost_weightOverall multiplier on slew overhead in the sequencer objective
slew_deg_per_sAssumed slew speed for overhead estimation
slew_settle_sPost-slew settle time added to every slew overhead
filter_change_cost_sTime cost of a filter wheel change
meridian_flip_cost_sTime cost of an equatorial mount meridian flip
preferred_target_boostScore boost applied to targets matching preferred_targets in the node’s profile
robustness_cloud_relaxCloud-cutoff relaxation bonus for nodes with an enclosure or dew heater
slot_quality_floorMinimum per-slot quality score below which a slot is rejected
local_search_aggressivenessAnnealing aggressiveness multiplier for the seeded local search

CHORUS hyperparameters

scheduler:
  chorus_params:
    scarcity_gamma: 0.93
    scarcity_horizon_nights: 45.0
    exploration_beta: 0.15
    same_site_repeat_factor: 0.25
These are seed values only — live values are stored in tuning_state. Changes to this group are additionally validated by the deterministic backtest replay (see CHORUS). The full key list and bounds are in cloud/chorus/params.py.
ParameterDescription
scarcity_gammaNightly discount factor on future capture chances in the T1 scarcity sweep
scarcity_horizon_nightsHow many future nights the T1 sweep looks ahead when pricing cells
exploration_betaValue placed on observations that reduce uncertainty about a node’s performance
same_site_repeat_factorWeather-correlation cap: limits how much the solver can harvest independent sky-survival from multiple placements at the same site

light_pollution

light_pollution:
  api_key: ''
ParameterDescription
api_keyAPI key for lightpollutionmap.info. When blank, all nodes default to 20.0 mpsas (a moderately light-polluted sky). Obtain a key at lightpollutionmap.info to fetch real sky-quality values for each node’s location

help

help:
  openrouter_api_key: ''
  model: anthropic/claude-haiku-4.5
ParameterDescription
openrouter_api_keyOpenRouter API key for the member Help chat assistant. Leave blank to fall back to the OPENROUTER_API_KEY environment variable
modelModel identifier used for the in-app AI help chat. Rate-limited to 5 user messages per week per member

storage

storage:
  raw_image_dir: cloud_data/raw_images
  raw_image_retention_days: 14
  max_image_mb: 64
ParameterDescription
raw_image_dirDirectory where uploaded raw FITS images are stored before the retention window expires
raw_image_retention_daysNumber of days to retain raw images before the daily maintenance loop prunes them
max_image_mbMaximum accepted size in megabytes for a single uploaded FITS image

logging

logging:
  level: INFO
  format: '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
ParameterDescription
levelPython logging level — DEBUG, INFO, WARNING, or ERROR
formatlogging.basicConfig format string applied to all cloud server log output

Database Schema

The schema is created automatically by db.init() on startup and all column migrations are applied idempotently — no manual DDL is ever needed.
TablePurpose
nodesOne row per registered telescope — location, hardware capability, autonomy flags, and nightly-recomputed performance metrics
targetsActive observation targets ingested from alert brokers
scoresLatest composite score for every (target, node) pair, with component breakdown
plansCurrent and superseded observation plans per node, stored as JSON
measurementsPhotometry results uploaded by node agents
aavso_batchesSubmission batch records with accept/reject counts
interruptsHigh-priority target alerts broadcast to nodes
tuning_stateSingle row holding live scoring weights and CHORUS hyperparameters for all tunable groups
weight_historyAudit trail of every weight change — includes old values, new values, Claude rationale, and evidence digest
chorus_node_ledgerPer-node Beta posteriors for p_exec, p_accept, κ, and site weather calibration
chorus_target_statePer-target cross-night state: EB phase-coverage vectors, CV hazard clocks, transient segment tracking
chorus_run_archiveFrozen opportunity inputs and realized outcomes per night — the data source for the Ring-1 backtest gate
The migration system (_COLUMN_MIGRATIONS in db.py) adds new columns to existing tables with ALTER TABLE … ADD COLUMN IF NOT EXISTS, so upgrading a production database is always a safe restart.

Build docs developers (and LLMs) love