ghagen
Generate GitHub Actions workflows from Python or TypeScript code.
Features
- Dual language support - The tool comes in two flavors depending on your constraints/preferences: Python and Javascript/Typescript.
- Typed models — type checking and IDE autocomplete which prevents typos or unsupported values.
- YAML comments — Add comments to the generated yaml for additional documentation/clarity
- Helpers — expression builder (
expr) ensures you are using supported template variables - Escape hatches — Break out of the type system when you want to. You're not stuck with the schema if new features come out or you need to override something.
- Linting — catch gotchas like invalid permissions and more.
timeout-minutes, and duplicate step ids with source-line precision - Freshness checking — ensure your generated yaml files are in sync with your defined ghagen models
- Version pinning — Prevent surprises and security risks by ensuring the same actions run every time.
Quickstart
Python
pip install ghagen # or: uv tool install ghagen
from ghagen import App, Job, On, PushTrigger, Step, Workflow
ci = Workflow(
name="CI",
on=On(push=PushTrigger(branches=["main"])),
jobs={
"test": Job(
runs_on="ubuntu-latest",
steps=[Step(uses="actions/checkout@v4"), Step(run="pytest")],
),
},
)
app = App()
app.add_workflow(ci, "ci.yml")
app.synth()
ghagen synth
TypeScript
npm install --save-dev @ghagen/ghagen
import { App, workflow, job, step, on, pushTrigger } from "@ghagen/ghagen";
const ci = workflow({
name: "CI",
on: on({ push: pushTrigger({ branches: ["main"] }) }),
jobs: {
test: job({
runsOn: "ubuntu-latest",
steps: [step({ uses: "actions/checkout@v4" }), step({ run: "pytest" })],
}),
},
});
const app = new App();
app.addWorkflow(ci, "ci.yml");
await app.synth();
npx ghagen synth
GitHub Action
Run ghagen check-synced in CI so a PR fails if the generated YAML drifts from the Python config:
jobs:
check-workflows:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nathanjordan/ghagen/check-synth@v0
with:
config: .github/ghagen_workflows.py # optional; default shown
python-version: "3.13" # optional; default shown
ghagen-version: "" # optional; empty = latest
v0 is a rolling major tag. The Action is a drift check for the Python path; TypeScript users can
run npx ghagen check-synced instead.
Example output
Both snippets above generate:
name: CI
on:
push:
branches:
- main
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pytest
FAQ
Python or TypeScript — which should I pick? Pick whatever you're comfortable with or fits with your project. Both Python and Typescript/Javscript implementations have feature parity and are interchangeable.
Can I mix ghagen-generated workflows with hand-written YAML? Yes. ghagen only touches files you
explicitly register. Any other file in .github/workflows/ is left alone — drop a hand-written
weekly-report.yml next to a ghagen-generated ci.yml and nothing breaks.
What does the GitHub Action do? It runs ghagen check-synced against your Python config and
fails the build if the generated YAML doesn't match what the current definitions would produce. It
prevents changes made to the Python/JS code from not making it into the YAML spec.
How do I handle something ghagen's models don't cover? Use extras on any model for arbitrary
keys, or Raw / raw() to drop an expression into a field that expects a literal. Both leave the
rest of the model fully typed.
How do I pin actions to commit SHAs? Run ghagen deps pin to populate
.github/ghagen.lock.toml; subsequent ghagen synth calls rewrite every uses: to its pinned SHA.
Wire ghagen deps check-synced into CI to catch unpinned additions.
More questions? See the full FAQ.
Documentation
Full documentation: nathanjordan.github.io/ghagen
License
MIT
Metadata
Release files for ghagen 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ghagen-0.5.0.tar.gz | 375.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ghagen-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 484.0 kB
Release files / ghagen-0.5.0.tar.gz
| Download URL | ghagen-0.5.0.tar.gz |
|---|---|
| Size | 375.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
936e39158d7625aa28b68f86337bdd9a5e0fc3d8b788d4038384e076c4e67bab
|
|
BLAKE2b-256 checksum How to use checksums |
4051edb92799972b4665b7844f14b4192c8a0498462793da44a1b7f8e675d2c8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Apr 21, 2026.
Transparency logRelease files / ghagen-0.5.0-py3-none-any.whl
| Download URL | ghagen-0.5.0-py3-none-any.whl |
|---|---|
| Size | 108.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0b1ad353da4533d5d9a19eecb37bdc5d4fdd2fa80fa84611a0b74573d2f371c3
|
|
BLAKE2b-256 checksum How to use checksums |
276c1bb2faa75ab327a92e755b92456a6a04b34c8c1d716f3106993a31e24d41
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
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 Apr 21, 2026.
Transparency log