Policy JSON schema#
A policy is the input that turns a universe of parsed easyconfig candidates
into one selection. It is a JSON object matching the Policy struct in
src/domain.rs.
1 Full shape#
{
"toolchain": {"name": "foss", "version": "2025b"},
"roots": ["GROMACS"],
"root_priority": ["GROMACS"],
"pins": [
{"name": "OpenBLAS", "version_req": "==0.3.24"}
],
"forbid": ["OpenMPI-4.1.5-foss-2025b.eb"],
"objective": "prefer_newer",
"require_upgrade": {"name": "GROMACS", "relative_to_baseline": true}
}
Only toolchain and roots are required; every other field defaults as
noted below.
2 Fields#
toolchain{"name": string, "version": string}. Required. Selects which candidates from the parsed tree participate: only easyconfigs whose owntoolchainmatches exactly are eligible.rootsArray of package names. Required, non-empty. Every dependency (runtime and build-time) a root needs co-selects automatically; the solve fails if any named root has no candidate at all.
root_priorityOptional array of package names. Declares which root wins the newest-version tie-break when two or more roots share a dependency with conflicting requirements. Defaults to
rootslist order when omitted or empty. Any root missing from an explicitroot_priorityis appended inrootsorder, so every root always participates. Reorderingrootsdoes not change the effective priority onceroot_priorityis set explicitly. See the how-to and why this exists.pinsOptional array of
{"name": string, "version_req": string}. Restricts a package to candidates whose version matches the requirement string (grammar below). A pin on a package with no matching candidate fails the solve at policy-construction time, before any SAT solving happens.forbidOptional array of strings. Each entry matches either a full
easyconfig_pathor a bare packagename; matching candidates are excluded from the universe entirely before solving.objectiveOptional string, default
"prefer_newer". The only objective eb-stack 0.2.0 supports: among jointly feasible assignments, prefer the newest version of each root (in priority order), then the newest version of every other co-selected package.require_upgradeOptional
{"name": string, "relative_to_baseline": bool}. Whenrelative_to_baselineis true, the named package’s solved version must be strictly newer than its version in the baseline lock (see--baseline-easyconfigs/--baseline). No baseline, or no baseline entry for that package, fails the solve with an explicit error instead of skipping the requirement without a warning.
3 versionreqgrammar#
Used by both pins[].version_req and parsed easyconfig dependency
requirements (==X, >=X, <=X, >X, <X, or a bare X for an exact
match). Version comparison is EasyBuild-shaped, not semver: digit runs
compare numerically, letter runs compare lexicographically, and a trailing
letter run with nothing on the other side sorts as a pre-release
(2025a < 2025b, 1.0rc1 < 1.0).
4 Effective root priority#
def effective_root_priority(policy):
order = policy.root_priority or policy.roots
order = [r for r in order if r in policy.roots] # only real roots
for r in policy.roots:
if r not in order:
order.append(r) # never drop a root
return order
This is a description of Policy::effective_root_priority in
src/domain.rs, not a separate implementation; it is shown here because the
outcome of a multi-root solve depends entirely on this order.
5 Where policies are consumed#
eb-stack stack solve --policy POLICY.json