What a config is: one expression in a pure declaration row. No IO appears in the type, so a config cannot escape into the world; the host folds it into a value.
Modulehorizon-config-0.8.0GHC2024
Horizon.Config
Everything a config script can name — the schema. This export list
is the config language: the package pins (hackage, git, tarball),
set metadata (name, description, platform, indexState), the
repository scope (license, warnings, language, extension,
nixConfig, and per local package exposed, internal, suite and
backend), the secure repository a pin may come from (hackageFrom),
the base the set is built on (a toolchain, or a lower set, each by
forge path and branch), the set-wide build policy (doJailbreak, doHaddock, …),
per-package facts (patch, systemDeps, systemDepFrom, cabal flags),
missing, the root markers, the export target, and Prelude. Nothing here performs
IO, so a config is a total description folded into an overlay or a
package set. :commands reflects exactly this surface, so the schema
is self-documenting.
- 26 types
- 47 values
- Packagehorizon-config-0.8.0
- Exports73
- LanguageGHC2024
- LicenceBSD-3-Clause
- SourceConfig.hs
Set the GHC compiler, e.g. compiler "ghc-9.10.1".
What the set is built on, exactly once:
on (toolchain (forge "nixlab.openfp.netpackage-setshaskellhorizon-build-packages") (branch "ltsghc-10.0.x"))
for a set built from scratch with a toolchain's compiler and build
tools, or on (set "horizon-core" (forge …) (branch …)) for an overlay
on a lower package set, which the set takes its compiler from and whose
packages it solves around at the versions that set holds. The base is
the generated flake.nix's one real input; the branch is what it
follows, and the flake lock records the commit. A config with no base
is an overlay for an application, which writes no flake.
A lower package set, as a base: set "horizon-core" (forge …) (branch …).
A toolchain root, as a base: toolchain (forge …) (branch …).
The platform the set is rendered for, as cabal names it: its packages'
arch(…) and os(…) conditionals are resolved for this target rather
than for the machine that runs the generator, e.g.
platform "javascript-ghcjs" for a set built by the JavaScript backend.
Undeclared, a set is rendered for x86_64-linux, whichever machine
generates it.
The Hackage index state the set is read at, e.g.
indexState "2025-03-01T00:00:00Z": each Hackage pin's revision is the
last one published by then, and a Solve against hackage chooses
among the releases Hackage had then, so nothing published later changes
the generated set. Undeclared, the newest the index the generator reads
holds.
The set's name (used for the generated module + flake description),
e.g. name "horizon-build-essentials".
A one-line description of the set.
The licence, as an SPDX identifier: license .MIT
The warnings contract: warnings "werrorwolf", every package also
built as a check with -Werror; warnings "none" for none.
The default language of the local packages: language .GHC2024
A default extension of the local packages, once per verb:
extension .OverloadedStrings
A nixConfig setting of the generated flake, key and value:
nixConfig "extra-substituters" "https://cache.openfp.net".
from DoBenchmark
from DoCheck
from DoHaddock
from DoJailbreak
from EnableProfiling
from IncludeBenchmarks
from IncludeExecutables
from IncludeTests
A package from Hackage at a pinned version.
Declare a secure cabal repository the set pins packages from, as a
cabal repository stanza does: its name, its URL, how many of the
root keys must sign its root metadata, and the root key ids, e.g.
repository "nixlab" "https://nixlab.openfp.net/hackage" 2 ["…", "…", "…"].
The generator fetches its index with cabal, which checks the
repository's signatures against these keys. A repository is declared
before the pins that name it.
A package at a pinned version from a declared repository instead of
Hackage: repository, name, version, e.g.
hackageFrom "nixlab" "vortex-trace" "0.3.0".
A package from a git repository at a revision.
The same, from a subdirectory of the repository: name, url, revision, subdirectory.
A package from a tarball URL: name, url.
The same, from a subdirectory of the unpacked tarball.
A LOCAL package: its source is a subdirectory of this config's own repo, not a fetched artifact — so a set can include a project developed alongside it (the code you are writing here): name, subdirectory.
Turn a cabal flag on for a declared package: package, flag.
Turn a cabal flag off for a declared package: package, flag.
Apply a source patch to a declared package: package, path to the
.patch/.diff file (which stays raw in the repo). A genuinely
per-package fact — the diff is specific to that package's source.
A native library whose callPackage argument is named differently
from the nixpkgs attribute that supplies it: package, argument,
attribute, e.g. systemDepFrom "cardano-crypto-class" "libblst" "blst".
A module a local package exposes: package, module, e.g.
exposed "tint" ; once per module.Tint.Diff
A module a local package keeps internal (other-modules).
A test suite of a local package: package, suite, the file it runs,
e.g. suite "tint" "laws" "Laws.hs".
A backend a local package builds for, once per backend:
backend "tint" "javascript". Undeclared, the native one.
Assert that a package is intentionally NOT provided by this set —
an architecture gap, no source, or deliberately unavailable. This is
the ONLY named absence (never a bare = null): the generator records
it, and if a root transitively needs a missing package that is a
hard error rather than a silent hole. (Packages that are merely
unreached under the set's policy are pruned, not declared missing.)
Export an overlay of the declared packages to this file, e.g.
overlay "overlay.nix". The default: what a library or an
application declares are the packages its base set is missing.
Export a whole package set to this file instead, e.g.
packageSet "initial-packages.nix", for a repository that builds
a package set from scratch.
Keep a package in the set for its own sake: the set exists to
provide it, not because something else in the set needs it. The
roots and everything they depend on are what the set must carry;
any other declaration is a pin nothing reaches, which
horizon-config --prune reports so it can be removed.
Declare a cabal index to resolve against, e.g. index "hackage" or
index "head.hackage". Declaration order is precedence (earlier =
higher): when a package is in several indices the resolved one comes
from the highest-precedence index carrying a usable version. Named
indices resolve to known repositories (hackage, head.hackage, and chap
for Cardano Haskell Packages) or to a repository the config declares
with Repository. Only meaningful with Solve.
Relax the upper version bounds on a package during the solve, e.g.
allowNewer "base" — the solve-time counterpart of a build-time
jailbreak. Needed when a bleeding-edge compiler ships a boot library
(base, template-haskell) newer than dependants' stated bounds. Changes
what the solver may pick, so it is declared, not assumed. Only
meaningful with Solve.
Expand the declared roots into the full transitive closure by
running the solver against the declared indices, writing the resolved
closure to the lock. Explicit: a config without solve uses its
literal hackage/git pins as written. A set has one closure, so
there is one solve.
A Hackage/package name: non-empty, no whitespace.
Constructors
Instances4Eq, Ord, Show, IsString
Eq PackageNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd PackageNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow PackageNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString PackageNameDefined in horizon-config-0.8.0 · Horizon.Config.Types
A GHC compiler spec, e.g. ghc-9.10.1 or ghc-10.0.x: non-empty and
beginning with ghc, which is all a config can meaningfully name here.
Constructors
Instances4Eq, Ord, Show, IsString
A package version, e.g. 2.2.3.0: non-empty, only digits and dots.
(x components as in an lts pin are a branch, not a package version, so
a package Version is strictly numeric.)
Constructors
A git commit revision: a hex string (a full 40-char SHA-1 or an unambiguous prefix of at least 7). This is what a flake pin locks to, so a non-hex value here is exactly the mistake worth catching early.
Constructors
Instances4Eq, Ord, Show, IsString
A git ref: a branch or tag name, e.g. lts/ghc-10.0.x or 0.24.0.
Non-empty, no whitespace; the human-readable branch a Revision is on.
Constructors
A subdirectory within a repo or tarball: non-empty, no whitespace. (The host still parses it into a real relative directory; this only rules out the obviously-bad literal at the DSL surface.)
Constructors
A cabal flag name: non-empty, no whitespace.
Constructors
Instances4Eq, Ord, Show, IsString
A target platform as cabal names it, ARCH-OS (javascript-ghcjs,
x86_64-linux): an architecture of letters, digits and underscores, a
dash, then the operating system. Whether cabal knows the architecture and
the system is the host's check, which has cabal's tables.
Constructors
Instances4Eq, Ord, Show, IsString
A Hackage index state, as cabal spells one: a UTC time to the second,
2025-03-01T00:00:00Z. Only the index entries published by then are
read, so a later revision cannot change what the set renders. The
literal must be the time's canonical spelling, which is the one form
cabal's index-state and cabal2nix's snapshot both accept.
Constructors
Instances4Eq, Ord, Show, IsString
Eq IndexStateDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd IndexStateDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow IndexStateDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString IndexStateDefined in horizon-config-0.8.0 · Horizon.Config.Types
A repository on a forge, named by host and path with no scheme:
nixlab.openfp.netpackage-setshaskell/horizon-core. The host is part
of the path so a config names the whole location and the generator holds
no forge of its own. Two or more segments, none empty, . or ..; a
host with a dot; nothing a URL would read as a scheme, query or fragment;
and a last segment, the repository, that is a SetName, since a
toolchain base is the flake input named for its repository.
Constructors
Instances4Eq, Ord, Show, IsString
The name a package set is known by, which is also its flake input in a set layered on it: a letter, then letters, digits, dashes and underscores.
Constructors
The name a config gives a secure cabal repository, which is also the
name cabal keeps the repository's index under (packages/NAME):
letters, digits, dots, dashes and underscores, e.g. nixlab.
Constructors
Instances4Eq, Ord, Show, IsString
Eq RepositoryNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd RepositoryNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow RepositoryNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString RepositoryNameDefined in horizon-config-0.8.0 · Horizon.Config.Types
A root key of a secure repository, as cabal's root-keys lists it: the
key id, 64 lowercase hex digits.
Constructors
A licence, as one SPDX licence identifier: MIT, BSD-3-Clause,
Apache-2.0, GPL-3.0-or-later. Letters, digits, ., - and +,
beginning with a letter; whether SPDX lists it is the generator's check.
The language a generated cabal declares as its default-language.
Instances6Bounded, Enum, Eq, Ord, Show, IsString
Bounded LanguageDefined in horizon-config-0.8.0 · Horizon.Config.TypesEnum LanguageDefined in horizon-config-0.8.0 · Horizon.Config.TypesEq LanguageDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd LanguageDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow LanguageDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString LanguageDefined in horizon-config-0.8.0 · Horizon.Config.Types
One GHC extension a generated cabal turns on by default
(default-extensions): OverloadedStrings, BlockArguments, or a
No-prefixed one that turns it off. A capitalised identifier; whether
GHC knows it is the generator's check.
Constructors
Instances4Eq, Ord, Show, IsString
The warnings contract of a repository's Haskell builds. werrorwolf
is the estate's: every package also builds as a check with
-Werror on top of its -Weverything. none declares no contract.
Instances6Bounded, Enum, Eq, Ord, Show, IsString
Bounded WarningsDefined in horizon-config-0.8.0 · Horizon.Config.TypesEnum WarningsDefined in horizon-config-0.8.0 · Horizon.Config.TypesEq WarningsDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd WarningsDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow WarningsDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString WarningsDefined in horizon-config-0.8.0 · Horizon.Config.Types
A Haskell module name as cabal lists one: dot-separated components,
each a capitalised identifier (Tint.Lexer.Cabal).
Constructors
Instances4Eq, Ord, Show, IsString
Eq ModuleNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd ModuleNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow ModuleNameDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString ModuleNameDefined in horizon-config-0.8.0 · Horizon.Config.Types
The name of a test suite, as cabal names a component: words of
letters and digits joined by -, each word holding a letter
(laws, golden-files).
Constructors
Instances4Eq, Ord, Show, IsString
The file a test suite runs, relative to its source directory, as
cabal's main-is names it: Main.hs, Laws.hs, Golden/Main.hs.
No empty, . or .. segment and no leading /; ends in .hs.
Constructors
A backend a package is built for: the native code generator, or GHC's JavaScript backend.
Instances6Bounded, Enum, Eq, Ord, Show, IsString
Bounded BackendDefined in horizon-config-0.8.0 · Horizon.Config.TypesEnum BackendDefined in horizon-config-0.8.0 · Horizon.Config.TypesEq BackendDefined in horizon-config-0.8.0 · Horizon.Config.TypesOrd BackendDefined in horizon-config-0.8.0 · Horizon.Config.TypesShow BackendDefined in horizon-config-0.8.0 · Horizon.Config.TypesIsString BackendDefined in horizon-config-0.8.0 · Horizon.Config.Types
Where a repository lives: forge "nixlab.openfp.net/…".
The branch a repository is followed on: branch "lts/ghc-10.0.x".
The commit is the flake lock's, not the config's.