astro-colibri-circular-parser
AI-assisted parsing of GCN circulars into structured, machine-readable multi-wavelength follow-up observations.
This is the extraction pipeline behind the GRB optical-afterglow feature of the Astro-COLIBRI multi-messenger astronomy platform, published as a standalone library. Given a circular (by number, URL, or raw text) it extracts reported observations — detections, upper limits, non-detections, X-ray/radio fluxes, redshifts — into a JSON record, with times normalised to seconds since trigger and optical photometry converted to a common observed-frame Rc-equivalent AB magnitude. As with any automated extraction, completeness and scientific values should be checked against the original circular before publication.
Associated manuscript: F. Schüssler et al., “AI-Assisted Extraction of Follow-up Observations from GCN Circulars in Astro-COLIBRI” (prepared for PASP; publication link to be added when available). Live service: the parsed results power the afterglow light curves at https://astro-colibri.com (documentation: https://astro-colibri.science/followupdoc).
How it works
circular number / URL ──► fetch (gcn.nasa.gov JSON archive)
│
▼
deterministic regex pre-analysis
(source names, photometry hints, contact emails)
│
▼
event resolution (optional, pluggable)
Astro-COLIBRI public API: trigger time, position, E(B-V)
│
▼
LLM structured extraction (OpenAI Responses API)
strict JSON schema; the regex hints are advisory input only
│
▼
photometric enrichment
filter normalisation → common Rc band (AB), Galactic-extinction
handling, absolute/relative time reconciliation vs. trigger
│
▼
follow-up payload + consistency checks (JSON)
Key design points:
- Structured outputs, not free text. The LLM must return JSON conforming to
a strict schema (
PHOTOMETRY_RESPONSE_SCHEMA); every object is closed (additionalProperties: false) and fully required, so missing values are explicitnulls. - Deterministic scaffolding around the LLM. Callers can use the exported
regex helpers as cheap prefilters;
parse_circular(...)itself always runs the configured extraction provider. Regex hints point the model at magnitudes, limits and redshifts, but the prompt requires the model to verify them against the circular. Consistency checks flag extractions that need human review (magnitudes without filters, unparseable times, negative times-since-trigger, ...). - Physics in code, not in the LLM. All photometric conversions (filter →
common Rc band, Vega↔AB, extinction re-reddening, time
arithmetic) are classical Python (
circular_parser/photometry.py), unit-tested and independent of the model. - No hidden state. The pipeline returns a plain dict; it performs no database writes and sends no notifications.
Install
git clone https://github.com/astro-transients/astro_colibri_circular_parser
cd astro_colibri_circular_parser
pip install . # library + CLI
pip install ".[examples]" # + notebook/plotting extras
Python ≥ 3.9. Dependencies: openai, requests, python-dateutil, and
python-dotenv (for CLI .env loading).
Configure
Copy .env.example to .env and set your OpenAI API key
(openAI_key or OPENAI_API_KEY). Never commit the key. All other
settings are optional; see the table in .env.example and
circular_parser/settings.py. A successful parse normally uses one LLM
request. Transient failures can trigger the configured retries, and semantic
time validation can invoke an optional fallback model. Provider billing
therefore depends on the selected model and number of attempts.
Quickstart
from circular_parser import parse_circular
result = parse_circular(45049) # fetches https://gcn.nasa.gov/circulars/45049
print(result["source_name"]) # EP260626a
print(result["consistency_issues"]) # []
for obs in result["payload"]["observations"]:
print(obs["observation_type"], obs["filter_raw"], obs["mag_raw"],
obs["time_since_trigger_s"], obs["corrected"]["mag_rc_ab_gal"])
Command line:
python -m circular_parser 45049 --pretty # full result to stdout
python -m circular_parser 45049 --output result.json # write to a file
python -m circular_parser 45049 --no-event-lookup # skip event linking
python -m circular_parser 45049 --offline examples/cached/extraction_45049.json # replays the LLM result
Cached extraction replay
The example notebook and the --offline CLI flag replay a cached extraction
(examples/cached/extraction_45049.json) without an OpenAI API key. Enrichment,
payload construction and consistency checks are identical to a live run.
The CLI flag replaces only the LLM request: when given a circular number or URL,
the CLI still retrieves the circular from GCN and performs event lookup unless
--no-event-lookup is also supplied. For a completely network-free run, use
the Python API with cached circular content, a replay provider, and either a
cached event= dictionary or resolve_events=False. The example notebook and
the test suite demonstrate this pattern; pytest tests/ needs no network or
credentials.
Human validation
Human review of stored reports belongs to the surrounding Astro-COLIBRI
platform rather than this standalone parser. The parser returns
consistency_issues and preserves the original circular text and provenance so
callers can implement their own review workflow. The live service is described
in the Astro-COLIBRI follow-up documentation.
Output data model
parse_circular(...) returns:
| key | content |
|---|---|
source_name |
resolved event name (e.g. GRB 260101A, EP260626a) |
event_resolved / event |
whether/which known event the circular was linked to |
circular |
number, subject, archive URL |
regexp_hints |
deterministic pre-analysis (advisory input to the LLM) |
extraction |
raw structured LLM output (PHOTOMETRY_RESPONSE_SCHEMA) |
payload |
enriched follow-up record: report metadata (observatory, instrument, authors, contacts, GCN link) + observations |
consistency_issues |
human-review flags |
Each observation in payload["observations"] carries the reported values
(filter_raw, mag_raw, mag_err, flux/flux_unit, time_raw, ...) plus
derived quantities: time_since_trigger_s, is_upper_limit, and corrected
(mag_ab, mag_rc_ab_gal — the observed-frame Rc-equivalent AB
magnitude used for light curves — beta, correction_status).
Event linking (Astro-COLIBRI)
To convert absolute observation times to times since trigger — and to attach
positions/extinction — the pipeline can resolve the circular against the
public, unauthenticated Astro-COLIBRI API (/event, /source_details). This
is optional: pass resolve_events=False to disable event lookup (relative
times like "26.5 hours after the trigger" still work), supply your own
event= dict, or plug in any other backend via EventLookup (three
callables). Avoiding all network access also requires passing circular content
directly instead of a circular number or URL. See circular_parser/events.py.
Examples
examples/parse_circular_demo.ipynb walks through: fetching a real circular,
the regex pre-analysis, an offline replay of a cached extraction (renders
fully without an API key), an optional live LLM extraction, and a light-curve
plot of the enriched photometry.
Tests
pip install ".[tests]"
pytest tests/
The test suite uses cached data and test doubles; no network access or API keys are required.
License and citation
BSD 3-Clause (see LICENSE). If you use this code in a publication, please use
the metadata in CITATION.cff to cite the associated manuscript (the final
publication reference will be added when available) and cite the Astro-COLIBRI
platform (Reichherzer et al. 2021, ApJS 256, 5).
Metadata
Release files for astro-colibri-circular-parser 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| astro_colibri_circular_parser-1.0.0.tar.gz | 62.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| astro_colibri_circular_parser-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 115.6 kB
Release files / astro_colibri_circular_parser-1.0.0.tar.gz
| Download URL | astro_colibri_circular_parser-1.0.0.tar.gz |
|---|---|
| Size | 62.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9e3a3f6d6e5188e7cdf8361df88e4ee1cc785a4cc5bd982b881ff9fb07707cc3
|
|
BLAKE2b-256 checksum How to use checksums |
e5d54ac9e2f21651f7e36b2fafb0c6670e38b8a68d872f4f66fdfbc19e58ef79
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency logRelease files / astro_colibri_circular_parser-1.0.0-py3-none-any.whl
| Download URL | astro_colibri_circular_parser-1.0.0-py3-none-any.whl |
|---|---|
| Size | 53.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
16ecce432b1b6a0b397a82e4bf27b6142f7bed4b2a61e2297bda94fc8ec96bea
|
|
BLAKE2b-256 checksum How to use checksums |
081fc8bd5ef534e325ca35b90c0e8877a0f18f4d2d68083f6fe7cf0820e48216
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 13, 2026.
Transparency log