Skip to content

Generated files

Some repo files are views of your fleet: the flake’s inputs, a README with the host diagram, a CI workflow. Write them from the data, and a check fails when a committed file is stale. denful/flake-file writes flake.nix. sini/files writes README.md and the CI workflow. yen gives both the content.

These docs are made this way: every page you read is a file that the docs fleet writes. So is yen’s CI workflow: each stage is an aspect, and one job per system comes from the reference fleet’s ci.json (docs/modules/ci.nix).

modules/fleet.nix
# The fleet writes its own repo files. `flake-file` collects github:denful/flake-file options (flake.nix);
# `files` collects github:sini/files modules (README.md, CI workflow).
{
yen,
lib,
inputs,
...
}:
let
pkgs = inputs.nixpkgs.legacyPackages.x86_64-linux;
in
{
yen.kinds.fleet = {
spawns.host = _: yen.host;
sinks = {
out.reduce = yen.lib.reduce.merge;
flake-file = {
reduce = yen.lib.reduce.merge; # flake inputs, declared by the aspects that use them
out =
{ flake-file, ... }:
let
e = inputs.nixpkgs-unstable.lib.evalModules {
# flake-file needs `valueMeta` on submodule options: nixos-25.05 lib lacks it
specialArgs = { inherit inputs; };
modules = [
inputs.flake-file.flakeModules.flake
{ inherit flake-file; }
{ flake-file.formatter = p: p.nixfmt-rfc-style; }
];
};
in
{
packages.x86_64-linux.write-flake = e.config.flake-file.apps.write-flake pkgs;
checks.x86_64-linux.flake-file = e.config.flake-file.check-flake-file pkgs;
};
};
files.out =
{ files, ... }:
let
e = lib.evalModules {
modules = [
inputs.files.module
{
_module.args.pkgs = pkgs;
files.root = inputs.self;
files.relativeRoot = "docs/examples/generated-files";
}
]
++ files;
};
in
{
packages.x86_64-linux.write-files = e.config.files.writer.drv;
checks.x86_64-linux = e.config.files.checks; # each committed file must match
};
};
};
yen.kinds.host.sinks.nixos.out =
{ host, nixos, ... }:
{
nixosConfigurations.${host.name} = inputs.nixpkgs.lib.nixosSystem { modules = nixos; };
};
yen.fleet.main = { };
yen.host.web = { };
yen.flake = { out, ... }: out;
}

Each aspect declares the flake inputs it uses on the flake-file sink. The host’s input goes up to the fleet:

modules/inputs.nix
# Each feature declares the inputs it uses, next to the code that uses them.
{ yen, ... }:
{
yen.aspects.core-inputs = {
at = yen.kinds.fleet;
flake-file = {
description = "A fleet that writes its own flake.nix, README.md and CI workflow";
outputs = ''
inputs:
inputs.yen.lib.mkFlake {
imports = [ (inputs.import-tree ./modules) ];
_module.args = {
inherit inputs;
inherit (inputs.nixpkgs) lib;
};
}
'';
inputs = {
yen.url = "github:vic/yen";
import-tree.url = "github:denful/import-tree";
flake-file.url = "github:denful/flake-file";
files.url = "github:sini/files";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable"; # flake-file's lib
};
};
};
yen.aspects.web = {
at = yen.host.web;
flake-file.inputs.nixpkgs.url = "https://nixos.org/channels/nixos-25.05/nixexprs.tar.xz"; # goes up to the fleet's `flake-file` sink
nixos = {
services.nginx.enable = true;
boot.loader.grub.device = "nodev";
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";
};
nixpkgs.hostPlatform = "x86_64-linux";
system.stateVersion = "25.05";
};
};
}

The files sink collects sini/files modules. One aspect writes the README, with a single mermaid diagram of the fleet’s hosts, and the CI workflow:

modules/write.nix
# README.md and the CI workflow, generated from fleet data by github:sini/files.
{ yen, lib, ... }:
let
hosts = lib.filter (s: s.kind == "host") yen.lib.graph.scopes;
in
{
yen.aspects.write = {
at = yen.kinds.fleet;
files = {
files.file."README.md".text = ''
# My fleet
Generated from the fleet. Hosts: ${lib.concatMapStringsSep ", " (s: "`${s.name}`") hosts}.
```mermaid
graph TD
fleet[main]
${lib.concatMapStringsSep "\n" (s: " fleet --> ${s.name}") hosts}

”; files.file.”.github/workflows/ci.yml”.text = ” name: ci on: [push, pull_request] jobs: check: runs-on: ubuntu-latest steps:

  • uses: actions/checkout@v4
  • uses: DeterminateSystems/nix-installer-action@main
  • run: nix flake check ”; }; }; }
The template's own `flake.nix` is the `flake-file` output. Remove the `web` aspect, and `nixpkgs` leaves the flake.
```nix title="flake.nix"
# DO-NOT-EDIT. This file was auto-generated using github:denful/flake-file.
# Use `nix run .#write-flake` to regenerate it.
{
description = "A fleet that writes its own flake.nix, README.md and CI workflow";
outputs =
inputs:
inputs.yen.lib.mkFlake {
imports = [ (inputs.import-tree ./modules) ];
_module.args = {
inherit inputs;
inherit (inputs.nixpkgs) lib;
};
};
inputs = {
files.url = "github:sini/files";
flake-file.url = "github:denful/flake-file";
import-tree.url = "github:denful/import-tree";
nixpkgs.url = "https://nixos.org/channels/nixos-25.05/nixexprs.tar.xz";
nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
yen.url = "github:vic/yen";
};
}
README.md
# My fleet
Generated from the fleet. Hosts: `web`.
```mermaid
graph TD
fleet[main]
fleet --> web
```text title=".github/workflows/ci.yml"
name: ci
on: [push, pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: DeterminateSystems/nix-installer-action@main
- run: nix flake check
Terminal window
nix run .#write-flake # write flake.nix
nix run .#write-files # write README.md and the CI workflow
nix flake check # fails when a committed file is stale
Contribute Community Sponsor