Skip to content

Recipes

A recipe is a measurement written down once, reviewed, referenced and versioned, so that two observers with two different instruments produce numbers that can be compared. spectro-kernel calls them presets in the code; this section uses both words for the same thing.

The problem recipes solve

Marc observes with an Alpy 600 in Toulouse, Sophie with a LHIRES III in Lyon. Both follow the Be star γ Cas and want to submit an Hα equivalent width to BeSS. Each writes their own pipeline file: Marc normalises on 6500–6520 Å, Sophie on 6480–6500 Å because she read something else; Marc integrates over 40 Å, Sophie over 30. Two numbers labelled "EW(Hα)" land in the database, measured differently, and a researcher cannot combine them. The bricks were the same; the convention was not shared, and it was tangled with each observer's instrument settings.

Three words

Word What it is Who writes it Where it lives
Brick one published algorithm (equivalent_width, normalize_to_region, ...) kernel contributors, with a reference the kernel, algorithm catalogue
Recipe which bricks, in which order, with which conventions; declares what depends on the instrument as variables the community, reviewed the kernel (a few generic ones) or a collection such as spectro-kernel-recipes
Profile the values for one instrument and one observer (slit tilt, extraction width, site) each observer or application your disk, your application

The variables are the contract between a recipe and a profile. A recipe never contains an instrument value; a profile never contains a scientific convention.

The same story, with recipes

The recipe fixes the science and asks only for what it cannot know, here the observer's site, needed to bring the wavelengths to the barycentric frame before measuring (BeSS stores spectra that way):

# be_halpha_ew.yaml  (from the collection, not from Marc's disk)
name: be_halpha_ew
version: 1.0.0
requires: ">=0.7"
description: H-alpha equivalent width and V/R of a Be star, measured the same way by every observer.
metadata:
  kind: campaign
  status: draft
  references: ["Vollmann & Eversberg 2006, AN 327, 862", "Neiner et al. 2011, AJ 142, 149"]
  conventions: "continuum band 6500-6520 Å, 60 Å window around H-alpha, V/R within 15 Å"
variables:
  latitude_deg:  {type: float, required: true, description: "observatory latitude (deg)"}
  longitude_deg: {type: float, required: true, description: "observatory longitude (deg, east)"}
steps:
  - algorithm: barycentric_correction
    params: {latitude_deg: "${latitude_deg}", longitude_deg: "${longitude_deg}"}
  - algorithm: normalize_to_region
    params: {wave_lo: 6500.0, wave_hi: 6520.0}       # fixed by the recipe
  - algorithm: equivalent_width
    params: {line_center_angstrom: 6562.79, window_angstrom: 60.0}
  - algorithm: vr_ratio
    params: {line_center_aa: 6562.79, window_half_width_aa: 15.0}

Marc's profile is two lines, with nothing scientific in it:

# toulouse.yaml
latitude_deg: 43.60
longitude_deg: 1.44

And the run binds the two:

spectro pipeline be_halpha_ew --input gamma_cas_2026-09-19.fits --profile toulouse.yaml

Sophie runs exactly the same command with lyon.yaml. Both results carry the same band, the same window, the same error formula, and each spectrum's history ends with a record naming the recipe, its version, the bound variables and the kernel version:

[ok] pipeline:be_halpha_ew v1.0.0 (412.3ms)
     variables={'latitude_deg': 43.6, 'longitude_deg': 1.44, 'elevation_m': 0.0}  kernel_version=0.7.0

That record is what lets a researcher say "these two measurements are comparable" and what lets you write "measured with recipe be_halpha_ew v1.0.0" in a report. The instrument geometry of a raw-frame reduction (slit tilt, extraction width) is handled the same way by the reduction recipes, solar_long_slit and stellar_long_slit.

In one minute

spectro presets                              # every recipe this install can see
spectro preset show snr_check                # its variables and steps
spectro pipeline snr_check --input obs.fits  # run one (no variables here)
spectro preset validate my_recipe.yaml       # check a recipe before sharing it

From Python:

from spectro_kernel import WorkContext
from spectro_kernel.pipeline import PipelineBuilder

pipeline = PipelineBuilder().from_preset("be_halpha_ew", {"latitude_deg": 43.6, "longitude_deg": 1.44}).build()
result = pipeline.execute(WorkContext(spectrum=spec))
print(result.history[-1])          # pipeline:be_halpha_ew v1.0.0 ...

From an MCP client, the run_preset tool takes the same variables.

Where to go next

  • Recipe format: the file, the variable types, the substitution rules, the requires range, the metadata vocabulary.
  • Catalogue: every recipe this documentation build can see, with conventions, references and variables.
  • Share a recipe: the three tiers, the spectro-kernel-recipes collection, how a draft becomes a reference.