Profiles and Hooks

Profiles and hooks adapt a base foga.yml without turning it into a collection of one-off scripts. Profiles handle environment-specific configuration. Hooks add small commands around generated backend commands.

Profiles

Profiles let one repository express environment-specific differences without copying the entire config. Apply them with --profile <name>.

Minimal example:

profiles:
  mpi:
    build:
      cpp:
        configure_args:
          - -DBUILD_CPP_TESTS=OFF
          - -DUSE_MPI=ON
      python:
        env:
          USE_MPI: "ON"

Typical uses:

  • CI versus local development

  • MPI versus non-MPI builds

  • platform-specific environment variables

  • release-only deployment settings

  • tool wrappers such as uv run or pipx run

Profile merge rules are intentionally conservative:

  • profile overrides may replace values and extend nested mappings

  • they must preserve the container type of existing paths

  • they cannot change the backend identifier of an already configured workflow

Hooks

Hooks are the supported escape hatch when a workflow needs a small amount of custom orchestration around a built-in backend command.

Minimal example:

test:
  runners:
    integration:
      backend: pytest
      path: tests
      hooks:
        pre:
          - ["python3", "tools/prepare_integration.py"]
        post:
          - ["python3", "tools/cleanup_integration.py"]

If you need to run a backend through a wrapper command, use launcher instead of a hook. For example:

format:
  targets:
    python-style:
      backend: ruff-format
      launcher: ["uv", "run"]
      paths: ["src", "tests"]

Supported behavior:

  • only hooks.pre and hooks.post are supported

  • each hook entry must be a non-empty command array

  • hooks run directly without shell parsing

  • hooks execute around the generated backend command

Intentionally unsupported:

  • shell strings such as "make build && make test"

  • per-hook mappings such as cwd, shell, argv, or inline env

  • turning the config file into a generic task runner

If logic is complex, keep it in a project script and call that script from a hook.