Command-line reference

eb-stack has five namespaced command groups plus an MCP server. All paths written by package commands are deterministic bundle artifacts.

Command map

Command

Purpose

package inspect

Parse conda-forge, Spack, PyPI, CRAN, Cargo, LuaRocks, or Raku into a manifest and planned SBOM

package plan

Materialize profiles, solve with Resolvo, and emit recipes

package bump

Retarget an EasyBuild recipe and write the same canonical bundle

recipe check

Validate metadata and robot dependency availability

recipe lint / recipe format

Report or mechanically repair EasyBuild E501 findings

stack solve / stack sbom

Solve a multi-root stack or emit SBOM from a lock

target list / target doctor

Resolve layered target configuration and probe it

campaign run / campaign status

Execute or inspect a persisted build campaign

campaign finding ...

Claim and resolve typed build findings

mcp

Serve the same workflows over stdio

Package commands

package inspect

eb-stack package inspect \
  --source PATH \
  --format auto|conda-forge|spack|pypi|cran|cargo|luarocks|raku \
  --toolchain-name foss \
  --toolchain-version 2026.1 \
  [--package-config PACKAGE.toml]... \
  --out-dir BUNDLE

This writes package.plan.json and package.sbom.cdx.json. It does not solve profiles or emit recipes, so it establishes no claim-ladder rung.

package plan

eb-stack package plan \
  --source PATH \
  --format conda-forge|spack|pypi|cran|cargo|luarocks|raku \
  --toolchain-name foss \
  --toolchain-version 2026.1 \
  [--package-config PACKAGE.toml]... \
  [--source-checksum SHA256]... \
  --easyconfigs UPSTREAM \
  [--easyconfigs OVERLAY]... \
  --stack-policy STACK.toml \
  [--package-catalog CATALOG.toml]... \
  [--package-sources SOURCES.toml]... \
  [--easybuild-source DIR]... \
  [--conda-source DIR]... \
  [--spack-source DIR]... \
  [--cargo-source DIR]... \
  --out-dir BUNDLE

Package configs apply in argument order; later metadata, build policy, aliases, and profile values override earlier layers. Later robot paths override earlier paths for the same EasyBuild identity. build.patches replaces the existing patch list by default. Set patches_mode = "merge" in the layer’s [build] table to retain foreign or preceding patches while adding or refining artifacts by filename. Each requested product profile is solved independently and emits one lock plus one conventional .eb file. The default profile has no suffix; non-default profiles use their declared versionsuffix.

Every emitted source needs a SHA-256 checksum. When a foreign recipe provides only a VCS commit, repeat --source-checksum once for every source artifact in manifest order. The values replace the positional source checksums in both the manifest/SBOM and every emitted recipe. Planning fails before emission when the count, shape, or completeness is invalid.

When a direct dependency has no compatible robot candidate, optional closure inputs close the hole without inventing versions:

  • --package-sources layers ordered EasyBuild / conda-forge / Spack / Cargo roots;

  • --easybuild-source, --conda-source, --spack-source, and --cargo-source push roots without a TOML file (order is discovery order);

  • --package-catalog layers explicit foreign or easybuild-bump providers as ordered overrides.

Robot candidates win over catalog entries. A closed plan writes companion packages under packages/, a shared easyconfigs/ overlay, topological build-order.json, and closure.sbom.cdx.json. See package bundles and the new-package how-to.

--format cargo reads Cargo.toml or crates.io JSON. A PyPI leftover whose run dependency is a PyO3 crate is closed by --cargo-source, not by a pip extra. Extra site packages that Warehouse omits belong in the ingest: a JSON array of Warehouse objects, or later requirements.txt lines. Resolvo then takes the robot module when --easyconfigs provides it. Do not hand-edit the emitted recipe for those names. A PEP 518 build_system object with build-backend = mesonpy is the mesonpy hint: listed requires become SAT build deps, and the emitter writes wrap_mode=default plus the shared cargo-on-EESSI isolation prelude (host wrappers off, LINKER=${CC:-gcc}, compat ld from uname -m). Hatchling stays a Python-bundle-PyPI module when the robot provides it. See site Python extras.

package bump

eb-stack package bump \
  --source RECIPE.eb \
  --toolchain-name foss \
  --toolchain-version 2024a \
  [--version VERSION] \
  [--source-checksum SHA256] \
  [--dep NAME=VERSION]... \
  --easyconfigs UPSTREAM \
  [--easyconfigs OVERLAY]... \
  [--hierarchy-fixture HIERARCHY.json] \
  [--stack-policy STACK.toml] \
  --out-dir BUNDLE

A bump writes the same manifest, planned SBOM, profile lock, and recipe layout as a new package. --dep becomes a locked Resolvo override. Without --stack-policy, the solver uses an unconstrained policy for the requested toolchain. A changed package version without --source-checksum produces a visible residual because source bytes cannot be inferred safely.

Bundle layout

BUNDLE/
  package.plan.json
  package.sbom.cdx.json
  locks/<profile>.lock.json
  easyconfigs/<letter>/<name>/<recipe>.eb

package plan and package bump establish the resolves claim only when all requested locks and recipes are written successfully.

See package bundle reference for the complete manifest, planned SBOM, profile-lock, residual, and recipe contract.

Recipe commands

eb-stack recipe check \
  --recipe RECIPE.eb \
  --easyconfigs UPSTREAM \
  [--easyconfigs OVERLAY]... \
  [--require-configopt FLAG]... \
  [--metadata-only]

eb-stack recipe lint RECIPE.eb [RECIPE.eb ...]
eb-stack recipe format RECIPE.eb [RECIPE.eb ...] [--dry-run]
eb-stack recipe format RECIPE.eb --out FORMATTED.eb

recipe check prints the structured dependency result. It fails when package metadata, checksum structure, required configuration flags, or robot dependencies are invalid. Missing dependencies remain explicit work; the command does not create placeholder recipes.

recipe format only performs deterministic physical-line wrapping. Product configuration, source selection, checksums, patches, and sanity paths remain authored content.

Stack commands

eb-stack stack solve \
  --easyconfigs TREE [--easyconfigs OVERLAY]... \
  --policy POLICY.json \
  [--baseline-easyconfigs TREE] \
  [--baseline-toolchain-version VERSION] \
  [--lock-out stack.lock.json] \
  [--sbom-out stack.cdx.json] \
  [--build-list-out build.list] \
  [--stack-diff-out stack.diff.md]

eb-stack stack sbom --lock stack.lock.json [--out stack.cdx.json]

stack solve is the multi-root EasyBuild stack solver. Package-profile stack preferences use the TOML schema documented with the package workflow; whole stack solving uses the JSON Policy schema.

Target commands

eb-stack target list --config BASE.toml [--config SITE.toml]...
eb-stack target doctor \
  --config BASE.toml [--config SITE.toml]... \
  --target NAME

Target layers are applied in argument order. A complete target contains:

  • transport: local or SSH;

  • executor: direct or Slurm;

  • runtime: host, Podman, or Docker;

  • EasyBuild workload: command, robot paths, work root, temporary root, and environment.

target doctor probes each layer separately and reports the exact routed command, exit code, stdout, and stderr.

See build target configuration for complete layer schemas, replacement semantics, ABI isolation, and the runnable local Podman target.

Campaign commands

eb-stack campaign run \
  --bundle BUNDLE \
  --config BASE.toml [--config SITE.toml]... \
  --target NAME \
  --state CAMPAIGN.json

eb-stack campaign status --state CAMPAIGN.json

eb-stack campaign finding claim \
  --state CAMPAIGN.json --id FINDING --owner WORKER

eb-stack campaign finding resolve \
  --state CAMPAIGN.json --id FINDING --owner WORKER \
  --action TEXT --evidence TEXT [--change PATH]...

campaign run resumes state with matching package identity, increments the attempt, stages the bundle, runs every emitted recipe, and executes each profile’s verification commands. Transport, executor, runtime, interrupted, checksum, patch, dependency, configure, compile, link, test, install, sanity, resource, timeout, and unknown failures are persisted as typed findings.

Finding claims are exclusive. A resolution records an action, evidence, and changed paths. A successful retry supersedes matching open or in-progress findings. Campaign state reports resolves, builds, and binary_verified independently.

See campaign state and typed findings for the serialized state, claim ladder, class/disposition table, and repair protocol.

MCP

eb-stack mcp

The stdio server exposes one tool per CLI workflow:

  • eb_package_inspect, eb_package_plan, eb_package_bump;

  • eb_recipe_check, eb_recipe_lint, eb_recipe_format;

  • eb_stack_solve, eb_stack_sbom;

  • eb_target_list, eb_target_doctor;

  • eb_campaign_run, eb_campaign_status;

  • eb_campaign_finding_claim, eb_campaign_finding_resolve.

MCP results include the same artifacts, claims, findings, and next actions as the CLI. There is no separate compatibility command surface.

eb_package_plan accepts the CLI’s repeated source-checksum input as a source_checksums string array, and the catalog / source-root inputs as package_catalogs, package_sources, easybuild_sources, conda_sources, and spack_sources arrays. eb_package_bump optionals include version, source_checksum, dependencies (object map), hierarchy_fixture, and stack_policy. eb_recipe_lint takes a recipes path array.