Skip to main content

Skycat logo

Skycat

Skycat is a standalone Python package and command-line tool for building, managing and querying versioned local PostgreSQL/PostGIS databases from mirrored astronomical reference catalogs.

It provides calibration, photometry, and observation-processing pipelines with a fast reproducible catalog layer that does not depend on the availability or performance of external catalog services. Skycat can discover and ingest known catalog releases, validate imported data, manage multiple versions of the same catalog, activate the release that should serve as the default, and retain older releases for reproducibility or comparison.

Its query interface supports spatial cone searches, catalog-native source lookups, magnitude and quality filtering, and efficient batch crossmatching using PostGIS spatial indexes. The overall goal is to provide astronomy software with a consistent, locally controlled source of catalog data for workflows that require reliable access to large astronomical reference catalogs.

Skycat installs:

  • the skycat CLI;
  • Python query APIs, including CatalogReader;
  • SQLAlchemy models and registry logic;
  • ingestion parsers, validators, and COPY loaders;
  • Alembic migrations under skycat/migrations;
  • support for APASS, VSX, Landolt, and Stetson catalog families.

Skycat does not install PostgreSQL, PostGIS, catalog source files, imported catalog rows, production credentials, backups, or a hosted query endpoint. Operators still provision the database and provide source data separately.

Supported Catalogs

Family Releases Source Rows
apass DR6, DR10 AAVSO APASS 42.6M / 128.6M
vsx current AAVSO VSX 10.3M
landolt 1992, 2009 CDS II/183A, J/AJ/137/4186 526 / 595
stetson StetsonGlobs CDS J/MNRAS/485/3042 4.89M

Installation

From PyPI:

python -m pip install skycat

From the GitHub Release wheel:

python -m pip install \
  https://github.com/SkynetRTN/skycat/releases/download/v0.1.6/skycat-0.1.6-py3-none-any.whl

From a Git tag:

python -m pip install "git+https://github.com/SkynetRTN/skycat.git@v0.1.6"

See docs/operations/release.md for release, artifact, TestPyPI, and PyPI validation steps.

Quick Start

For local development:

uv sync --extra dev
uv run skycat --help

For a local PostgreSQL/PostGIS catalog database:

cp infra/docker/.env.example infra/docker/.env
cp infra/docker/.env.secrets.example infra/docker/.env.secrets
docker compose -f infra/docker/compose.yaml build skycat-postgres
docker compose -f infra/docker/compose.yaml up -d skycat-postgres
docker compose -f infra/docker/compose.yaml --profile skycat-tools run --rm skycat-init
docker compose -f infra/docker/compose.yaml --profile skycat-tools run --rm skycat-migrate

Then point SKYCAT_DATA_ROOT at mirrored source data, discover releases, and import deliberately:

export SKYCAT_DATA_ROOT=/srv/agents/catalogs
uv run skycat discover
uv run skycat import apass dr6 --activate
uv run skycat cone apass --ra 10.0 --dec 1.0 --radius-arcmin 5

The operational details are in docs/operations/runbook.md.

CLI

Run skycat --help for the full command list. The main commands are:

Command Purpose
config Show resolved configuration.
init Create roles, grants, schemas, PostGIS, and migrations.
migrate / migrate-status Apply or inspect Alembic migrations.
discover Discover local source releases.
import Ingest, validate, mark ready, and optionally activate a release.
activate / deactivate Change the default active release for a family.
releases / history Inspect release and ingestion state.
cone / crossmatch / lookup Query catalog rows.
validate Re-validate an imported production partition.
health Run read-only health checks.
sizes Report table and index sizes.
clean-staging / remove-release / reset Maintenance and guarded destructive operations.

Examples:

skycat --json config
skycat releases apass
skycat cone apass --ra 10.0 --dec 1.0 --radius-arcmin 5 --order-by johnson_v_mag --limit 50
skycat lookup apass 090-0000001

--json is a group option, so it goes before the subcommand.

Python API

Use CatalogReader for application reads. It owns connection pooling, active release caching, and a default statement timeout. Query calls re-check a cached release against the registry before using it, so a release removed, failed, or deactivated behind a long-lived reader raises CatalogQueryError instead of looking like an empty cone.

from skycat import CatalogReader

with CatalogReader.from_env() as reader:
    stars = reader.cone(
        "apass",
        ra=10.0,
        dec=1.0,
        radius_arcmin=5,
        order_by="johnson_v_mag",
        limit=50,
    )
    hits = reader.crossmatch("vsx", [("target-1", 10.0, 1.0)], radius_arcsec=5)
    row = reader.lookup("apass", "090-0000001")

Pass order_by whenever you also pass limit. Without it, cone results are nearest-first by angular separation, which is not the same as brightest-first in dense fields.

See docs/reference/api-stability.md for the stable API surface and compatibility policy.

Release Model

Catalog releases are a database dimension, not a deployment artifact. Each family can have multiple imported releases, but only one active release serves default queries at a time. Use --release when you need a specific historical release for parity checks, rollback, or reproducibility.

Imports stage rows, validate them, build production partitions, mark releases ready, and activate only when explicitly requested. A failed import should not degrade the currently active release.

Re-running skycat import <family> <release> --activate is idempotent for an unchanged imported release: if it is already ACTIVE the command exits 0, and if it is READY or SUPERSEDED the command activates it when the validation gate allows activation.

The full architecture is documented in docs/reference/architecture.md, and source data provenance is covered in docs/guides/provenance.md.

Configuration

Skycat uses SKYCAT_DB_* for database settings and SKYCAT_* for catalog runtime paths and diagnostics.

Variable Default Purpose
SKYCAT_DB_BACKEND postgresql+psycopg SQLAlchemy backend.
SKYCAT_DB_HOST 127.0.0.1 Database host.
SKYCAT_DB_PORT 5433 Host-side Compose port; use 5432 inside Compose.
SKYCAT_DB_NAME catalogs Catalog database name.
SKYCAT_DB_USER / SKYCAT_DB_PASSWORD catalog_reader / unset Default query identity.
SKYCAT_DB_SSLMODE unset libpq SSL mode.
SKYCAT_DB_POOL_SIZE / SKYCAT_DB_MAX_OVERFLOW 10 / 5 Reader pool sizing.
SKYCAT_DB_POOL_RECYCLE / SKYCAT_DB_POOL_TIMEOUT 300 / 30 Pool recycle and checkout timing.
SKYCAT_DB_POOL_PRE_PING true Detect stale pooled connections.
SKYCAT_DB_ECHO false SQL echo logging.
SKYCAT_DB_STATEMENT_TIMEOUT unset Reader/default statement timeout in milliseconds. Does not apply to ingest, admin, or bootstrap connections.
SKYCAT_DB_{BOOTSTRAP,ADMIN,INGEST,READER}_STATEMENT_TIMEOUT unset Role-specific statement timeout override in milliseconds.
SKYCAT_DB_LOCK_TIMEOUT 5000 Phase B2 import swap lock timeout in milliseconds; each retry waits at most this long for the family parent.
SKYCAT_DB_BOOTSTRAP_USER / SKYCAT_DB_BOOTSTRAP_PASSWORD unset DBA/bootstrap identity for init.
SKYCAT_DB_ADMIN_USER / SKYCAT_DB_ADMIN_PASSWORD unset Owner/migrator identity.
SKYCAT_DB_INGEST_USER / SKYCAT_DB_INGEST_PASSWORD unset Bulk-ingestion identity.
SKYCAT_DB_READER_USER / SKYCAT_DB_READER_PASSWORD unset Read-only role managed by init.
SKYCAT_DATA_ROOT /srv/agents/catalogs Read-only catalog source root.
SKYCAT_WORK_ROOT /tmp/skycat-work Writable work area for manifests, rejects, and checkpoints.
SKYCAT_DEBUG unset Diagnosis only: suppress the CLI's friendly error messages entirely, so the original exception and its traceback reach the interpreter. Leave it unset in Jobs and services — with it set, an error is a stack trace instead of a message.

Testing

Fast tests do not require a database:

uv run pytest tests -q -m "not postgis"

PostGIS tests require a throwaway catalog database. Do not point them at a catalog store you care about; fixtures import small samples with replacement.

uv run skycat health
uv run pytest tests -q --require-postgis

See docs/operations/ci.md for the CI matrix and docs/operations/runbook.md for operational safety notes.

Adding a Catalog Family

The implementation guide is docs/guides/add-family.md. The short checklist is:

  1. Add a FamilyDef / ReleaseDef in skycat/registry/catalog_defs.py.
  2. Add a typed model under skycat/models/.
  3. Add a streaming parser under skycat/ingestion/parsers/.
  4. Add an Alembic migration under skycat/migrations/versions/.
  5. Add family-specific validation under skycat/validation/ when needed.
  6. Add fixtures, tests, and a row in the supported-catalog table above.

Documentation

Document Use it for
docs/reference/architecture.md Database model, release lifecycle, spatial representation, deployment shape.
docs/reference/api-stability.md Stable Python, CLI, configuration, and database contracts.
docs/guides/add-family.md Worked guide for adding a new catalog family.
docs/guides/provenance.md Source mirroring and release provenance.
docs/operations/runbook.md Destructive-operation safety, incident checks, credential rotation.
docs/operations/performance.md Query targets and tuning guidance.
docs/operations/ci.md Required checks and workflow behavior.
docs/operations/release.md GitHub Releases, TestPyPI, and PyPI publishing.
docs/decisions/ Architecture decisions.

Working notes live under docs/working/; they are snapshots of open work, not current API references.

License

Skycat is licensed under the GNU General Public License v3.0. See LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

skycat-0.1.6.tar.gz (2.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

skycat-0.1.6-py3-none-any.whl (122.3 kB view details)

Uploaded Python 3

File details

Details for the file skycat-0.1.6.tar.gz.

File metadata

  • Download URL: skycat-0.1.6.tar.gz
  • Upload date:
  • Size: 2.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for skycat-0.1.6.tar.gz
Algorithm Hash digest
SHA256 7d74da6cc3868442fbfeca9b888240ae2928477e5ab112a596ff7e4dfb3e67b1
MD5 a5d98ad97e9770b7155610a776b3bdad
BLAKE2b-256 4e2182fbcbd340144cf19bd859c17177a24ee55f3c58453d62fe7bbbde1de28a

See more details on using hashes here.

Provenance

The following attestation bundles were made for skycat-0.1.6.tar.gz:

Publisher: release.yml on SkynetRTN/skycat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file skycat-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: skycat-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 122.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for skycat-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 4815035d9707cecf6fb6baf2be6c8c745bdb92285a18794d837465b288a5b187
MD5 80ee0b743d4adc6f7d4a9eeefc4a2d6c
BLAKE2b-256 a74cc5cb7cebcadd334921d8884ef288b61f1846551d6ba37eedc82717e79a64

See more details on using hashes here.

Provenance

The following attestation bundles were made for skycat-0.1.6-py3-none-any.whl:

Publisher: release.yml on SkynetRTN/skycat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page