Writing Recipes

Current Format v3
Extension .stars
Legacy Formats v1, v2, dir

Astral recipes are .stars files that describe how to download, build, and install a package. There are four recipe formats use v3 for anything new.

Too lazy to write a recipe from scratch? astral-recipegen interactive v3 will scaffold one for you.

Format Overview

FormatStatusMarker
v3recommended$PKG.Version = "3"
v2supported$PKG.Metadata: { ... }
v1deprecated@BUILD
dirancientdirectory with build file

v3 Format

The current standard. Separates build-time and runtime dependencies, supports git sources, post-install hooks, and optional deps.

$PKG.Version = "3"

$PKG.Metadata: {
    Version = "1.2.3"
    Description = "A short one-line description"
    Homepage = "https://example.com"
    Category = "app-misc"
    License = "GPL-3.0"
};

$PKG.Depend.BDepends: {
    gcc
    make
    cmake >= 3.20
};

$PKG.Depend.RDepends: {
    glibc
    ncurses >= 6.0
    zlib
};

$PKG.Depend.Optional: {
    bash-completion
};

$PKG.Sources: {
    urls = "https://example.com/pkg-1.2.3.tar.xz"
};

$PKG.Checksums: {
    sha256:abc123def456... pkg-1.2.3.tar.xz
};

$PKG.Build: {
    cd pkg-1.2.3
    ./configure --prefix=/usr
    make -j$(nproc)
};

$PKG.Package: {
    cd pkg-1.2.3
    make DESTDIR="$PKGDIR" install
};

$PKG.PostInstall: {
    ldconfig
};

$PKG.PostRemove: {
    echo "pkg removed."
};

All Sections

Metadata

Required. Describes the package.

KeyRequiredDescription
VersionyesPackage version string (e.g. "2.7.6")
DescriptionnoOne-line description
HomepagenoProject URL
Categorynoe.g. sys-libs, app-editors, dev-util
LicensenoSPDX identifier e.g. GPL-3.0, MIT

Dependencies

SectionDescription
BDependsBuild-time only compilers, build tools. Removed after build.
RDependsRuntime libraries, interpreters. Kept forever.
OptionalExtra features user can skip during install.
PDependsPost-install time dependencies.
IDependsInstall-time dependencies.

Version constraints:

ncurses >= 6.0
readline = 8.2
python < 3.12
cmake          # any version

Operators: =, >=, <=, >, <

Sources

URLs to download. Supports multiple sources and git repos.

# Tarball
$PKG.Sources: {
    urls = "https://example.com/pkg-1.2.3.tar.xz"
};

# Multiple sources / patches
$PKG.Sources: {
    urls = "https://example.com/source.tar.gz"
    urls = "https://example.com/fix-001.patch"
};

# Git source
$PKG.Sources: {
    urls = "git+https://github.com/user/repo#branch=main"
};

# Git by tag
$PKG.Sources: {
    urls = "git+https://github.com/user/repo#tag=v1.2.3"
};

Checksums

SHA256 hashes for downloaded files. Git sources don't need them.

$PKG.Checksums: {
    sha256:fb53c30b...  source.tar.gz
    sha256:9a3bc1d2...  fix-001.patch
};

Build

Shell commands to compile the package. Runs in a sandbox. Has access to $CFLAGS, $CXXFLAGS, $MAKEFLAGS.

# Autotools
$PKG.Build: {
    cd pkg-1.2.3
    ./configure --prefix=/usr --sysconfdir=/etc
    make -j$(nproc)
};

# CMake
$PKG.Build: {
    cd pkg-1.2.3
    cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
    cmake --build build -j$(nproc)
};

# Meson
$PKG.Build: {
    cd pkg-1.2.3
    meson setup build --prefix=/usr --buildtype=release
    ninja -C build -j$(nproc)
};

# Architecture-specific
$PKG.Build [IF arch=x86_64]: {
    ./configure --prefix=/usr --enable-avx2
    make -j$(nproc)
};

$PKG.Build [IF arch=aarch64]: {
    ./configure --prefix=/usr --enable-neon
    make -j$(nproc)
};

Arch conditions: x86_64, aarch64, riscv64, armv7h, i686

Package

Installs built files into $PKGDIR (the staging directory). Never write to / directly.

$PKG.Package: {
    cd pkg-1.2.3
    make DESTDIR="$PKGDIR" install

    # CMake
    DESTDIR="$PKGDIR" cmake --install build

    # Meson
    DESTDIR="$PKGDIR" ninja -C build install

    # Manual
    install -Dm755 mybinary "$PKGDIR/usr/bin/mybinary"
    install -Dm644 mylib.so "$PKGDIR/usr/lib/mylib.so"
    install -Dm644 myapp.1  "$PKGDIR/usr/share/man/man1/myapp.1"

    # Symlinks
    ln -sf /usr/bin/myapp "$PKGDIR/usr/bin/app"
};

PostInstall / PostRemove

Shell hooks that run after installation or removal, on the real system (not $PKGDIR).

$PKG.PostInstall: {
    ldconfig
    update-desktop-database
    glib-compile-schemas /usr/share/glib-2.0/schemas
};

$PKG.PostRemove: {
    echo "pkg removed. config files in /etc/ remain."
};

Recipe Generator

astral-recipegen automates most of the boilerplate.

CommandDescription
astral-recipegen interactive v3Guided wizard prompts for all fields
astral-recipegen auto <name> <url>Downloads source, detects build system, generates recipe
astral-recipegen template cmake v3Output a blank CMake v3 template
astral-recipegen template autotools v3Autotools template
astral-recipegen template meson v3Meson template
astral-recipegen migrate old.stars v3Convert v1/v2 recipe to v3
astral-recipegen dir-to-stars /path/to/dirConvert dir-format recipe to .stars
astral-recipegen from-pkgbuild PKGBUILD v3Convert Arch PKGBUILD (experimental)

Best Practices

  • Always use v3 for new recipes.
  • Put compilers/build tools in BDepends, libraries in RDepends. Don't mix them.
  • Always include checksums for tarball sources.
  • Always use $PKGDIR / DESTDIR never install directly to /usr.
  • Keep build scripts simple. Complex logic belongs in the upstream build system.
  • Use -j$(nproc) in make/ninja for parallel builds.
  • Run astral --validate your-recipe.stars before submitting.

Never run make install without DESTDIR="$PKGDIR". It will install directly to your live system and break everything.

Migrating Old Recipes

# v1 or v2 → v3
astral-recipegen migrate old-recipe.stars v3

# dir-format → v3
astral-recipegen dir-to-stars /usr/src/astral/recipes/app-editors/nano

Always review the output manually after migrating especially the dependency split between BDepends and RDepends, which the tool guesses at.