ghagen
Quick Install
Section titled “Quick Install”pip install ghagen uv add ghagen npm install @ghagen/ghagen yarn add @ghagen/ghagen pnpm add @ghagen/ghagen bun add @ghagen/ghagen Example
Section titled “Example”Define your workflow in code:
from ghagen import App, Job, On, PRTrigger, PushTrigger, Step, Workflow
workflow = Workflow( name="CI", on=On( push=PushTrigger(branches=["main"]), pull_request=PRTrigger(branches=["main"]), ), jobs={ "test": Job( runs_on="ubuntu-latest", steps=[ Step(uses="actions/checkout@v4"), Step(name="Run tests", run="python -m pytest"), ], ), },)
app = App()app.add_workflow(workflow, "ci.yml")app.synth()import { App, workflow, job, step, on, pushTrigger, prTrigger,} from "@ghagen/ghagen";
const ci = workflow({ name: "CI", on: on({ push: pushTrigger({ branches: ["main"] }), pullRequest: prTrigger({ branches: ["main"] }), }), jobs: { test: job({ runsOn: "ubuntu-latest", steps: [ step({ uses: "actions/checkout@v4" }), step({ name: "Run tests", run: "python -m pytest" }), ], }), },});
const app = new App();app.addWorkflow(ci, "ci.yml");await app.synth();ghagen generates clean, readable YAML:
name: CIon: pull_request: branches: - main push: branches: - mainjobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run tests run: python -m pytestFeatures
Section titled “Features”- Typed models for workflows, jobs, steps, triggers, and permissions
- IDE autocomplete and type checking for every field
- YAML comment support — block, end-of-line, and field-level comments
- DRY helpers — step factories (
checkout(),setupPython(), etc.) and expression builders - Escape hatches — graduated ways to inject arbitrary YAML when the typed models don’t cover what you need
- CLI —
ghagen synthto generate,ghagen check-syncedto verify freshness in CI,ghagen deps pinto lock actions to commit SHAs
Why ghagen?
Section titled “Why ghagen?”GitHub Actions are defined as YAML, which is simple and readable for small projects. As projects grow, however, workflows accumulate shared concerns and repeated logic — the same setup steps, the same version strings, the same conditional blocks copied across files. YAML has no real answer for code reuse: you end up changing the same value in multiple places, and configuration drift between workflows that should behave identically becomes a constant source of bugs.
GitHub has tried to address this with composite actions and YAML anchors, but the fundamental issue remains: YAML is a data format, not a programming language. Rather than bolting programming-language features onto YAML, ghagen takes the approach AWS CDK proved out for CloudFormation — use a real programming language to define your configuration, and generate the YAML from it.
ghagen also tackles a second problem: GitHub Actions dependencies (uses: "setup-node@v2") have no lockfile, so every workflow run can pull a different version. This makes builds non-hermetic and opens the door to supply-chain attacks via package takeovers. Tools like Ratchet address this; ghagen does too, with a lockfile you update explicitly via ghagen deps pin.
Next Steps
Section titled “Next Steps”- Cookbook — recipes for common workflow patterns
- Python API Reference — full Python model documentation
- TypeScript API Reference — full TypeScript API documentation