pf-ci — lower the CI DAG to workflows

pf-ci is the second lowering of the projectfile toolchain: it turns the org.projectfile.ci extension — a dependency-ordered DAG of CI goals — into the workflow files a forge actually runs.

Step Tool What it does
1. Read / write pf-cli get, set, add, del, validate, convert
2. Sync files pf-bridge package.json, CITATION.cff, README.md, …
3. Lower to CI pf-ci (this page) org.projectfile.ci → workflow YAML

Release binary

Latest release 3.4.0. Published for 5 platforms: macOS, Linux.

Terminal window
base=https://kiota.ch/projectfile/ci/releases/download/v3.4.0curl --fail --location --output ~/.local/bin/pf-ci \    "$base/pf-ci-$(uname -s | tr A-Z a-z)-$(uname -m)"chmod +x ~/.local/bin/pf-ci
PlatformAsset
macOS / ARM64pf-ci-darwin-arm64
macOS / x86-64pf-ci-darwin-x86_64

Verify what you downloaded

Every binary ships a detached signature beside it. Confirm it with the maintainer's release key, which the keyserver serves:

Terminal window
gpg --keyserver hkps://keys.openpgp.org --recv-keys 8F89CBF7C8D51F8BEC7533C00925F8F79EBD3257curl --fail --location --output pf-ci.asc \    "https://kiota.ch/projectfile/ci/releases/download/v3.4.0/pf-ci-$(uname -s | tr A-Z a-z)-$(uname -m).asc"gpg --verify pf-ci.asc ~/.local/bin/pf-ci

Container image

Run the tool without installing it. The alias makes every command on this site work unchanged against your working directory:

ghcr.io/projectfile-org/ci — linux/amd64, linux/arm64, linux/riscv64

Terminal window
docker pull ghcr.io/projectfile-org/ci:3.4.0alias pf-ci='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \    --volume "$PWD:/app/ws" --workdir /app/ws ghcr.io/projectfile-org/ci:3.4.0 pf-ci'

damianbuho/projectfile-ci — linux/amd64

Terminal window
docker pull damianbuho/projectfile-ci:3.4.0alias pf-ci='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \    --volume "$PWD:/app/ws" --workdir /app/ws damianbuho/projectfile-ci:3.4.0 pf-ci'

kiota.ch/projectfile/ci — linux/amd64

Terminal window
docker pull kiota.ch/projectfile/ci:3.4.0alias pf-ci='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \    --volume "$PWD:/app/ws" --workdir /app/ws kiota.ch/projectfile/ci:3.4.0 pf-ci'

Stable releases also publish X.Y.Z, X.Y and X tags — pull the precision you want to pin.

Uninstall

Terminal window
rm -f ~/.local/bin/pf-ci          # release binarydocker image rm ghcr.io/projectfile-org/ci   # container image
pf-ci resolve  [-pf PATH] [-verbose|-q]pf-ci generate -target gha|forgejo|lefthook [-pf PATH] [-o PATH] [-check|-n] [-force=false] [-verbose|-q]pf-ci help [COMMAND]pf-ci version
CommandWhat it does
resolveEmit the vendor-neutral job model as JSON (the template input).
generateRender the job model to a target’s workflow YAML, or (-check) verify the committed workflow still matches the source DAG.
helpPrint this help, or one command’s flags (also: pf-ci COMMAND -h).
versionPrint the resolver version (the codegen provenance stamp).

4 commands — the listing pf-ci v3.4.0 reported when the page was built.

Terminal window
pf-ci resolve                          # the whole job model as JSONpf-ci resolve -pf projectfile.yaml     # read a specific documentpf-ci resolve -q                       # mute progress; the verdict still prints
Terminal window
pf-ci generate -target gha        # render .github/workflows/*.yamlpf-ci generate -target forgejo    # render .forgejo/workflows/*.yamlpf-ci generate -target lefthook   # render lefthook.yamlpf-ci generate -check             # freshness gate: fail if the committed workflow driftedpf-ci generate -target gha -n     # print the write plan, change nothing
Flag Description
-target render target: forgejo, gha, lefthook
-pf projectfile path, or - for a YAML/JSON document on stdin (default: discover)
-o output directory for the per-goal workflow files (default: the target’s dir)
-check exit non-zero if the committed workflow drifted from the source DAG
-dry-run print the write/remove plan on stdout and change nothing
-force remove orphaned generated workflows; -force=false reports and fails instead
-quiet mute progress lines; warnings, errors and the verdict still print
-verbose show operational log lines (e.g. interpolation lookups)
Variable Effect
PF_CI_WORKFLOW_EXT committed-workflow file extension, .yaml or .yml. m6e’s make act-* derives its default from the same variable
PF_CLI_VERBOSE same effect as -verbose, for a run that cannot pass flags

A projectfile declares its pipeline as a set of named nodes with their dependencies; pf-ci walks that graph and emits one job per node:

org:  projectfile:    ci:      nodes:        site-is-built:          needs:            container-is-ok: true            dist-extract: true        inputs-are-ok:          needs:            specification-generated: true

Nothing in the emitted workflow is hardcoded: the lifecycle runs the nodes the document declares, and an empty org.projectfile.ci produces an empty pipeline.

pf-ci generate -check is the command that keeps a repository honest — it re-renders from the document and fails when the committed workflow files no longer match, so a hand-edited workflow or a changed DAG is caught before it ships. Run it as a CI step of its own:

- name: Verify CI workflows match org.projectfile.ci  run: pf-ci generate -target gha -check

.onion.i2p