pf-cli — read, write and validate
pf-cli is the command-line frontend for the projectfile: it reads, writes and
validates fields, resolves remote includes, and generates derived artifacts. It
embeds the v1 JSON Schema for offline validation and is the canonical tool for
editing projectfiles locally and in CI. Its extension namespace is
org.projectfile.cli.
File and forge sync lives in pf-bridge, not here — pf-cli has no bridge,
scan or forge commands. This page matches pf-cli --help exactly.
| Step | Tool | What it does |
|---|---|---|
| 1. Read / write | pf-cli (this page) | get, set, add, del, validate, convert |
| 2. Sync files | pf-bridge | package.json, CITATION.cff, README.md, … |
| 3. Lower to CI | pf-ci | org.projectfile.ci → workflow YAML |
Installation
Section titled “Installation”Release binary
Latest release 3.4.10. Published for 5 platforms: macOS, Linux.
base=https://kiota.ch/projectfile/cli/releases/download/v3.4.10curl --fail --location --output ~/.local/bin/pf-cli \ "$base/pf-cli-$(uname -s | tr A-Z a-z)-$(uname -m)"chmod +x ~/.local/bin/pf-cli| Platform | Asset |
|---|---|
| macOS / ARM64 | pf-cli-darwin-arm64 |
| macOS / x86-64 | pf-cli-darwin-x86_64 |
base=https://kiota.ch/projectfile/cli/releases/download/v3.4.10curl --fail --location --output ~/.local/bin/pf-cli \ "$base/pf-cli-$(uname -s | tr A-Z a-z)-$(uname -m)"chmod +x ~/.local/bin/pf-cli| Platform | Asset |
|---|---|
| Linux / ARM64 | pf-cli-linux-aarch64 |
| Linux / RISC-V | pf-cli-linux-riscv64 |
| Linux / x86-64 | pf-cli-linux-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:
gpg --keyserver hkps://keys.openpgp.org --recv-keys 8F89CBF7C8D51F8BEC7533C00925F8F79EBD3257curl --fail --location --output pf-cli.asc \ "https://kiota.ch/projectfile/cli/releases/download/v3.4.10/pf-cli-$(uname -s | tr A-Z a-z)-$(uname -m).asc"gpg --verify pf-cli.asc ~/.local/bin/pf-cliContainer 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/cli — linux/amd64, linux/arm64, linux/riscv64
docker pull ghcr.io/projectfile-org/cli:3.4.10alias pf-cli='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \ --volume "$PWD:/app/ws" --workdir /app/ws ghcr.io/projectfile-org/cli:3.4.10 pf-cli'damianbuho/projectfile-cli — linux/amd64
docker pull damianbuho/projectfile-cli:3.4.10alias pf-cli='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \ --volume "$PWD:/app/ws" --workdir /app/ws damianbuho/projectfile-cli:3.4.10 pf-cli'kiota.ch/projectfile/cli — linux/amd64
docker pull kiota.ch/projectfile/cli:3.4.10alias pf-cli='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 \ --volume "$PWD:/app/ws" --workdir /app/ws kiota.ch/projectfile/cli:3.4.10 pf-cli'Stable releases also publish X.Y.Z, X.Y and X tags — pull the precision you want to pin.
Uninstall
rm -f ~/.local/bin/pf-cli # release binarydocker image rm ghcr.io/projectfile-org/cli # container imageCommands
Section titled “Commands”The tool’s own listing, so a command added upstream appears here without a page edit; the sections below then cover the ones a project touches most.
| Command | Group | What it does |
|---|---|---|
get | Read | Read one or more projectfile fields |
add | Write | Append items to a projectfile list |
del | Write | Remove a field, list item, or map entry from projectfile |
set | Write | Write a value into a projectfile field |
validate | Validate | Validate a projectfile against the v1 JSON Schema |
cache | Maintain | Manage pf-cli’s local cache for offline use |
convert | Maintain | Convert a projectfile between encodings (toml/yaml/json) |
includes | Maintain | Manage the includes list |
init | Maintain | Scaffold a new projectfile document |
optimize | Maintain | Remove local fields that duplicate include values |
setup | Maintain | Edit your per-user configuration interactively |
completion | Other | Generate the autocompletion script for the specified shell |
help | Other | Help about any command |
13 commands — the listing pf-cli v3.4.10 reported when the page was built.
Read values out of the projectfile by path. Prints plain text, one value per
line. Exits 3 when a path is missing, 2 when the invocation is wrong. With
--suggest a missing path prints the nearest existing address instead.
pf-cli get <path>… [flags]pf-cli get identity.namepf-cli get repositories[role=origin].urlpf-cli get identity.bogus --suggestpf-cli get repositories[].urlpf-cli get identity --format jsonpf-cli get org.projectfile.sinks.kiota.ref --scope org.projectfile.image| Flag | Description |
|---|---|
--batch |
read several paths in one run |
--default <value> |
value to print when the path is missing |
--exists |
exit 0 if present, 1 if absent; prints nothing |
--expand |
fill ${…} from the document; leave the rest as written |
--expand-env |
fill ${VAR} from the environment first |
--file <path> |
explicit projectfile path (skips detection) |
--format |
raw, json, yaml, toml, sh, flat |
--lang <tag> |
choose a language for translated fields |
--or-default |
use the built-in default if missing |
--path KEY=ADDR |
label a path as KEY=ADDR (repeatable) |
--print-path |
print the projectfile path and exit |
--scope <address> |
fill ${…} from this address (repeatable) |
--suggest |
on a missing path, print the nearest existing address instead |
Replace the value at <path>. A bare value is stored as text, exactly as
typed. Use --value-json or --csv for a typed value. Missing sections are
created.
pf-cli set <path> [value] [flags]pf-cli set license.spdx MITpf-cli set identity.version 1.10pf-cli set keywords --csv rust,wasmpf-cli set contacts --value-json '{"email":"a@example.com"}'| Flag | Description |
|---|---|
--create-only |
fail if the path already has a value |
--csv <list> |
value as a comma-separated string list |
--dry-run |
show the write without saving it |
--value-json <j> |
value as JSON (a bare value is text) |
Append items to the list at <path>. Skips items that are already there.
pf-cli add <path> [value…] [flags]pf-cli add keywords rust wasmpf-cli add repositories --field url=https://example.com/rpf-cli add keywords rust -n| Flag | Description |
|---|---|
--allow-duplicate |
append even if already present |
--dry-run |
show the append without saving it |
--field k=v |
set one item field as k=v (repeatable) |
--value-json <j> |
the whole item as JSON |
Delete the value at <path>. Missing paths are not an error. Alias: delete.
pf-cli del <path> [flags]pf-cli del keywords[0]pf-cli del keywords[99] --strict| Flag | Description |
|---|---|
--dry-run |
show the deletion without saving it |
--strict |
exit 1 when the path is already absent |
Validate
Section titled “Validate”validate
Section titled “validate”Check that the projectfile is well-formed. Warns about repeated includes.
Alias: lint.
pf-cli validate [directory] [flags]pf-cli validatepf-cli validate /tmp/demopf-cli validate --strict-includes| Flag | Description |
|---|---|
--strict-includes |
fail on repeated includes (default: warn) |
Maintain
Section titled “Maintain”Create a new projectfile.yaml (or .toml/.json) in [directory]. With
pf-bridge installed this delegates to pf-bridge-init: full detection from
sources (package.json, CITATION.cff, …) plus scanner gap-fill (git history,
stack detection). Without it, a basic local scaffold prompts for namespace, name
and title only — no scanners. Alias: scaffold.
pf-cli init [directory] [flags]pf-cli initpf-cli init /tmp/demo --namespace org.example --name demo --non-interactive| Flag | Description |
|---|---|
--format |
output format: yaml, toml, json (default: prompt) |
--license <spdx> |
license SPDX expression (e.g. MIT) |
--name <slug> |
identity.name (project slug) |
--namespace <rdns> |
identity.namespace (reverse-DNS, e.g. org.example) |
--no-scan |
skip init-time scanners |
--non-interactive |
fail if required fields are missing instead of prompting |
convert
Section titled “convert”Rewrite the projectfile from one format to another. Checks the result before
writing; keeps the source file. Alias: conv.
pf-cli convert <from-format> <to-format> [directory] [flags]pf-cli convert yaml tomlpf-cli convert yaml json --delete-sourcepf-cli convert toml yaml --force| Flag | Description |
|---|---|
--delete-source |
remove the source file after converting |
--force |
overwrite the output file if it already exists |
Supported formats: toml, yaml (or yml), json.
optimize
Section titled “optimize”Remove values your includes already provide. Keeps includes, $schema and
spec_version. Alias: opt.
pf-cli optimize [directory] [flags]pf-cli optimizepf-cli optimize --dry-run| Flag | Description |
|---|---|
--dry-run |
list removals without saving |
includes
Section titled “includes”Manage the includes list.
pf-cli includes [command]| Subcommand | Description |
|---|---|
pin |
pin remote includes to the SHA-256 of their current bytes |
Keep downloaded includes on disk for offline reads. Shared with pf-bridge and
pf-ci.
pf-cli cache [command]| Subcommand | Description |
|---|---|
purge |
delete cached includes (all, or one URL) |
refresh |
alias for cache warm --force |
status |
show what is cached and where |
warm |
download includes now so later reads work offline |
pf-cli cache statuspf-cli cache warmAnswer questions once; answers prefill future prompts. Enter accepts, Esc skips a section.
pf-cli setup [flags]pf-cli setuppf-cli setup --format yamlPersonal defaults live at $XDG_CONFIG_HOME/projectfile/cli.{yaml,toml,json}.
Fields set there (author name, ORCID, funding URLs, preferred format, …)
pre-fill init prompts and renderer templates so the same flag is not repeated
on every project.
Exit codes
Section titled “Exit codes”Each failure class has its own code, so a script can tell a bad invocation from an absent field from an invalid document:
| Code | Meaning |
|---|---|
| 0 | success |
| 1 | the run failed: a parse error, no document found, a refused write |
| 2 | the invocation is wrong: unknown command, bad flag, bad path grammar |
| 3 | the requested path is absent (also --exists on an absent path) |
| 4 | the document does not validate against the v1 JSON Schema |
Global flags
Section titled “Global flags”| Flag | Description |
|---|---|
--colors |
colour output: auto, always, never; also PF_CLI_NO_COLOR=1 |
--fail-on |
abort includes at error or warning (default error) |
--ignore-user-config |
skip $XDG_CONFIG_HOME/projectfile/cli.* loading |
--offline |
refuse network; use cache and embedded data |
-q, --quiet |
mute info; warnings and errors still print |
--sorted |
write YAML keys in sorted order |
--timeout <duration> |
per-attempt network timeout (default 10s) |
-v, --verbose |
show each step; also PF_CLI_VERBOSE=1 |
-V, --version |
print the version |