Skip to main content

GitHub Workflow Manager CLI

Lint Code Base version codecov Python

ghwm CLI

Install managed GitHub workflow files from a central marketplace repository.

Workflows can be sourced from the official ghwfxlab/ghwm-registry or your own registry repository (see Create your own registry). Workflow authors can annotate packages with presentation metadata using commented YAML frontmatter.

Why ghwm?

Teams copy the same GitHub Actions workflows from repository to repository. Over time the copies drift, nobody knows which version or edit is running where, and security fixes never reach every repository.

ghwm treats workflows as versioned packages. You list them in ghwm.yml, ghwm install writes them to .github/workflows/, and ghwm.lock records exactly what was installed. Updates keep your local on: triggers by default, and files that ghwm does not manage are skipped unless you pass --force.

  • Compared with reusable workflows: a reusable workflow is called remotely, so the logic lives outside your repository and you can't tune the file. ghwm installs a real file you can read, review and adjust.
  • Compared with starter workflows: a starter workflow is a one-time copy with no update path. ghwm tracks versions and hashes, so ghwm update brings in new releases.

Built-in security

Run ghwm audit to scan every managed workflow with zizmor and get a Security Score from 0 to 100. It exits with 1 on High or Medium findings, so it works as a CI gate. See Auditing Workflows.

Install

The recommended way to install ghwm is using uv (a fast Python package manager):

uv tool install git+https://github.com/ghwfxlab/ghwm.git

Or pin to a specific version tag:

uv tool install git+https://github.com/ghwfxlab/ghwm.git@vX.Y.Z

Alternatives

If you prefer to install using pipx:

pipx install git+https://github.com/ghwfxlab/ghwm.git

Or via standard pip (into an active virtual environment):

pip install git+https://github.com/ghwfxlab/ghwm.git

Usage

1. Create ghwm.yml in your repository root

source: owner/ghwm-registry

workflows:
  - name: linter
    version: "1.0.0"
  - name: auto-assign-pr
    version: "1.0.0"
    source: other-owner/other-registry # (Optional) Override the global registry source
    update-triggers: true
    update-envs: true
    update-config-files: true

version is required for registry installs. By default, workflows are resolved from the global source. You can override this on a per-workflow basis using the source property. The CLI resolves each workflow to a GitHub Packages npm package named @<source owner>/<name>.

If you want to override the generated workflow filename, add target: my-review.yml to the workflow entry. For the complete schema, field types, and defaults, see the Manifest and Lockfile Reference.

2. Install workflows

ghwm install            # installs workflows listed in ghwm.yml
ghwm install --force    # overwrites even if files were modified locally
ghwm install --no-prune # skip removal of stale workflows
ghwm install --update-triggers # replace workflow triggers with the packaged version
ghwm install --update-envs # replace workflow env variables with the packaged version
ghwm upgrade            # automatically resolve, pin, and install latest versions
ghwm update             # re-downloads all workflows (respects versions)
ghwm update --prune     # also removes managed workflows no longer in ghwm.yml
ghwm update --update-triggers # replace workflow triggers with the packaged version
ghwm update --update-envs # replace workflow env variables with the packaged version
ghwm list               # shows workflows declared in ghwm.yml
ghwm audit              # audits managed workflows for security vulnerabilities

Workflow files are written to .github/workflows/ with a managed header. Additional packaged files such as config files are written as-is. On first install, config files are only created if the target does not already exist. On update, config files are only overwritten when update-config-files: true is set for that workflow.

File type First install Update Prune
Workflow file (.github/workflows/*) Install with managed header Update in place; preserve existing on: by default Remove
Packaged config file Create only when missing Overwrite only with update-config-files: true Keep

Managed files

Every installed workflow file starts with a header that marks it as managed:

# Managed by ghwm (linter@0.1.4)
# Source: @owner/linter:linter.yml
# Hash: sha256:...
# Re-run `ghwm install` to refresh this file.

The CLI uses this header to:

  • Distinguish managed files from hand-crafted ones (unmanaged files are never overwritten without --force).
  • Preserve existing on: rules during updates unless update-triggers: true or --update-triggers is used.
  • Preserve existing env: variables during updates unless update-envs: true or --update-envs is used.
  • Prune stale workflow files that were removed from the manifest.

Config files do not get a managed header and are never removed during prune.

Use ghwm update --prune when you want one command to refresh workflows that are still in ghwm.yml and remove managed workflows that were deleted from the manifest. It updates ghwm.lock too.

Lockfile

ghwm.lock is a JSON file that records every installed package and the files it manages:

{
  "lockfileVersion": 1,
  "packages": [
    {
      "name": "auto-assign-pr",
      "version": "2.0.0",
      "source": "@owner/auto-assign-pr",
      "files": [
        {
          "target": ".github/workflows/auto-assign-pr.yaml",
          "source_hash": "sha256:..."
        },
        {
          "target": ".github/auto_assign.yaml",
          "source_hash": "sha256:...",
          "overwrite": false
        }
      ]
    }
  ]
}

Commit ghwm.lock alongside ghwm.yml so CI and teammates install the exact same workflow package set. Old tarball-era lockfiles are rejected and must be regenerated.

Auditing Workflows (Security Scoring)

Since workflows are imported from shared registry repositories, keeping them secure is critical. The ghwm audit command runs static security analysis on all your installed/managed workflows using zizmor (a fast security linter for GitHub Actions).

ghwm audit

If the linter is not installed locally, ghwm will attempt to execute it dynamically using uvx zizmor.

ghwm audit calculates a Security Score out of 100 on a logarithmic scale (exponential decay) to ensure the score never goes negative:

$$\text{Score} = \text{round}\left(100 \times e^{-\text{Deductions} / 100}\right)$$

where total Deductions are calculated from:

  • High severity: 20 points
  • Medium severity: 10 points
  • Low severity: 5 points
  • Informational: 1 point

If any High or Medium severity vulnerabilities are detected, ghwm audit exits with code 1, making it ideal for integration into CI pipelines.

Keep Workflows Updated (Renovate Integration)

Since ghwm resolves workflows to npm packages (e.g., @owner/<name>) published to GitHub Packages, you can use Renovate to automatically detect updates and open pull requests to update the versions in your ghwm.yml.

Add the following regexManagers configuration to your renovate.json or renovate.json5 file:

{
  "regexManagers": [
    {
      "fileMatch": ["^ghwm\\.yml$"],
      "matchStrings": [
        "name:\\s+(?<depName>\\S+)\\s+version:\\s+[\"']?(?<currentValue>[^\"'\\s]+)[\"']?"
      ],
      "datasourceTemplate": "npm",
      "depNameTemplate": "@owner/{{depName}}",
      "registryUrlTemplates": ["https://npm.pkg.github.com"]
    }
  ]
}

Note: Replace @owner with the GitHub organization or username where your registry packages are published.

Authentication

The CLI needs read access to GitHub Packages and the marketplace repository. The CLI looks for authentication in the following order:

  1. Active gh CLI credentials (using the output of gh auth token)
  2. GH_TOKEN environment variable
  3. GITHUB_TOKEN environment variable

For example, you can set an environment variable:

export GH_TOKEN=ghp_...
# or
export GITHUB_TOKEN=ghp_...

If you rely on the gh CLI, ensure that its active token has read:packages access. You can add this scope if needed by running:

gh auth refresh -s read:packages

Local Development

Point at a local checkout of the registry for testing:

ghwm install --local ../ghwm-registry

With --local, the CLI reads workflows/<name>/workflow.yml directly from the checkout instead of downloading the npm package tarball.

Telemetry & Privacy

ghwm collects anonymous, privacy-gated usage telemetry to understand which workflow packages are being adopted. Here is exactly what is tracked and what is not:

What is tracked:

Field Example
Registry source owner/ghwm-registry
Workflow name linter
Workflow version 1.2.3
Event type install (first time added) or updated (workflow changed on re-install)
Workflow metadata (optional) Title, description, tags, icon, owner, version, source, created_at (see Workflow Frontmatter Specification)

What is never tracked: IP addresses, hostnames, usernames, file paths, repository names, environment variables, or any other system or user information.

Privacy gate

Telemetry is only emitted when the workflow registry is a public GitHub repository. Before sending any data, ghwm calls the GitHub REST API (GET /repos/{owner}/{repo}) without authentication to check the visibility of each workflow's resolved source registry. If a registry is private, internal, or if the check fails for any reason (network error, rate limit, missing permissions), telemetry is skipped silently for that workflow and the install continues normally.

This means workflows sourced from private or internal enterprise registries are never tracked, protecting proprietary workflow IP.

Opting out

You can disable telemetry for a single run with the --no-telemetry flag:

ghwm install --no-telemetry
ghwm update --no-telemetry
ghwm upgrade --no-telemetry

To opt out permanently — for example in CI/CD pipelines or a global shell config — set either the DO_NOT_TRACK=1 environment variable (consoledonottrack.com) or GHWM_NO_TELEMETRY=1:

export DO_NOT_TRACK=1
# or
export GHWM_NO_TELEMETRY=1

Create your own registry

A registry is a GitHub repository whose workflows/ folder holds one npm package per workflow, published to GitHub Packages. The official ghwfxlab/ghwm-registry is a good reference to copy from.

  1. Create a repository, for example my-org/ghwm-registry. The owner becomes the npm scope (@my-org/<name>).

  2. Add a folder per workflow, such as workflows/linter/, containing the workflow file, any config files, a package.json and a workflow.yml:

    # workflows/linter/workflow.yml
    name: linter
    files:
      - source: linter.yaml
        target: .github/workflows/linter.yaml
    

    Optionally add commented frontmatter with a title, description and tags.

  3. Set "name": "@my-org/linter" and "publishConfig": {"registry": "https://npm.pkg.github.com"} in package.json, and list the same files under "files".

  4. Test locally from a consumer repository, without publishing:

    ghwm install --local ../ghwm-registry
    
  5. Publish each package to GitHub Packages (the official registry does this from a publish workflow on every push to main), then set the package visibility to Public if consumers outside your organization need it.

  6. Point consumers at it in ghwm.yml:

    source: my-org/ghwm-registry
    workflows:
      - linter@1.0.0
    

Development

make install          # uv sync (dev deps)
make test             # pytest
make lint             # ruff check
make format           # ruff format
make type-check       # mypy
make lang             # textlint for prose/documentation
make precommit        # run pre-commit hooks on all files
make super-linter     # run super-linter via Docker
make clean            # remove build artifacts

Architecture

See ARCHITECTURE.md for design details.

License

MIT

Metadata

Release files for ghwm 1.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ghwm 1.10.0
File Size Uploaded
ghwm-1.10.0.tar.gz 275.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ghwm 1.10.0
File Interpreter ABI Platform
ghwm-1.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 306.7 kB

Release files / ghwm-1.10.0.tar.gz

Download URL ghwm-1.10.0.tar.gz
Size 275.5 kB
Tags Source
SHA-256 checksum
How to use checksums
b19afa3500db6e117edbb8fde31b73dbd63b7df6d98c0a42a6199e43f9c61d9a
BLAKE2b-256 checksum
How to use checksums
19b9e57b2b80e9d6d7f7e2b556f9d0c91ca2518b67bd6c78e97919c010591b6a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / ghwm-1.10.0-py3-none-any.whl

Download URL ghwm-1.10.0-py3-none-any.whl
Size 31.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e8dae2648c494825499c7ec3e022f1096d0c7772c33194a0c74eeec48d1b1f37
BLAKE2b-256 checksum
How to use checksums
bf1ffe27ec02f03a57ed3c53ee03a17f0af26f4a983c8de4468527944dab3978
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.10.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page