This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a Nix flake that provides a flake-parts module for generating GitHub Actions workflow files from type-safe Nix configuration. It converts Nix attribute sets into YAML workflow files that can be committed to .github/workflows/.
nix fmtFormats all Nix files using alejandra formatter.
nix developProvides a shell with development tools and automatically installs git hooks via hk.
Available tools:
- Core:
yq-go,hk - Nix formatters/linters:
alejandra,deadnix,statix - GitHub Actions linter:
actionlint - Configuration formatters:
pkl,prettier
Git hooks are automatically installed on shell entry and will run:
- pre-commit: Auto-format and lint with stashing of unstaged changes
- pre-push: Check-only mode for all linters
- Manual commands:
hk check,hk fix
# Evaluate the workflows directory to see generated files
nix eval .#githubActions.workflowsDir --raw
# Build example workflows
cd examples/basic
nix build .#workflows
# Generated workflows will be in result/.github/workflows/The module system is split into multiple focused files for better organization:
Entry point that ties everything together:
- Imports type definitions from
modules/types/workflow.nix - Imports conversion functions from
modules/converters.nix - Defines flake-parts perSystem options:
githubActions.enable: Enable/disable workflow generationgithubActions.workflows: Attribute set of workflow definitionsgithubActions.workflowsDir: Read-only output containing all generated workflow filesgithubActions.workflowFiles: Read-only output with individual workflow files
- Uses
yq-goto convert JSON to pretty-printed YAML with automatic header comment
Comprehensive type system that mirrors GitHub Actions YAML schema:
step.nix - Individual workflow steps:
stepType: Defines step options (name, id, run, uses, with_, env, etc.)- Handles both action-based steps (
uses) and shell command steps (run)
job.nix - Job configurations:
jobType: Job definitions with steps, strategy, permissions, container, services, etc.strategyType: Matrix build configurations with fail-fast and max-parallel optionspermissionsType: GITHUB_TOKEN permissions (either "read-all"/"write-all" or granular)
workflow.nix - Complete workflows and triggers:
workflowType: Top-level workflow with name, triggers, jobs, and global settings- Trigger types:
pushTriggerType,pullRequestTriggerType,scheduleTriggerType,workflowDispatchType - Supports workflow defaults for both run commands and job settings
Transforms Nix structures to YAML-compatible format:
filterNulls: Removes null values from attribute setsstepToYaml: Converts step configuration, handling special fields likeif_→if,with_→withjobToYaml: Converts job configuration with strategy and permissionstriggerToYaml: Handles both simple list format and detailed trigger configurationapplyJobDefaults: Applies workflow-level defaults to individual jobsworkflowToYaml: Top-level workflow conversion that orchestrates all other converters
- Exports two module paths:
flakeModules.defaultandflakeModules.githubActions(both point to same module) - Supports four system architectures: x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin
- Uses flake-parts partitions to isolate development dependencies:
- Main flake has minimal inputs:
nixpkgs,flake-parts - Development tools (
hkand linters) are indev/partition - Consumers won't see development dependencies in their lock files
- Main flake has minimal inputs:
Development inputs and configuration are isolated in a separate partition to avoid polluting consumers' lock files:
dev/flake.nix: Contains development-only inputs
hkfor git hooks managementnixpkgs(follows main flake's nixpkgs)
dev/flake-module.nix: Defines the development shell
- All development tools (formatters, linters, etc.)
shellHookthat automatically runshk installon shell entry
hk.pkl: Git hooks configuration
- Configures pre-commit, pre-push, check, and fix hooks
- Defines which linters to run and in what mode
This partition setup ensures that when other projects use this flake as an input, they only get the essential dependencies (nixpkgs, flake-parts) in their lock file, not the ~400+ development dependencies from hk and Rust toolchain.
Several Nix field names differ from their YAML equivalents to avoid conflicts with Nix keywords:
if_→ifwith_→withpull_requestusespullRequestin Nixworkflow_dispatchusesworkflowDispatchin Nix- Hyphenated YAML fields use camelCase in Nix (e.g.,
runsOn→runs-on,continueOnError→continue-on-error)
- User defines workflows in
githubActions.workflowsattribute set - Each workflow is validated against
workflowType workflowToYamlconverts Nix structure to JSON-compatible formatrunCommandderivations executeyq-goto convert JSON to formatted YAML- Individual files are combined into
workflowsDirderivation - Users copy from
workflowsDirto.github/workflows/in their repository
Two complete examples in examples/:
basic/: Simple CI workflow with build and lint jobsadvanced/: Matrix builds, release workflows with job dependencies and outputs, scheduled workflows
Both examples create a packages.workflows derivation that can be built with nix build .#workflows to generate the workflow files.
When modifying development tools or shell configuration:
- Edit
dev/flake-module.nixto add/remove packages or modify shellHook - Edit
hk.pklto configure git hooks behavior - Update
dev/flake.nixonly if adding new development inputs - After modifying
dev/flake.nix, runcd dev && nix flake lockto update the dev lock file - Test with
nix developto ensure hooks install correctly
When adding new workflow features:
- Add type definition in the appropriate module under
modules/types/:- Step-level options →
modules/types/step.nix - Job-level options →
modules/types/job.nix - Workflow-level options or triggers →
modules/types/workflow.nix
- Step-level options →
- Update corresponding
*ToYamlconversion function inmodules/converters.nixto handle the new field - Ensure proper null filtering with
filterNulls - If adding a new type file, import it in the appropriate dependent module
- Test with both basic and advanced examples
When debugging workflow generation:
- Check the JSON output:
nix eval .#githubActions.workflows.<name> --json - Verify the YAML conversion manually with yq-go
- Compare against examples/ for working patterns
- If types aren't being recognized, check the import chain:
step.nix← imported byjob.nixjob.nix← imported byworkflow.nixworkflow.nixandconverters.nix← imported bygithub-ci.nix