omniflake

Adding or removing a flake

Adding

manual.txt lists flakes the pipeline does not index on its own. It is read on every run, one entry per line:

nix-community/disko
github:nix-community/disko
github:owner/repo/v1.2.3
gitlab:owner/repo

A GitHub repository's default branch is resolved like a harvested one however it is spelled: the first two lines above are the same entry. Anything else — a tag, a subdirectory, another forge — is beyond the GitHub API, so nix flake metadata pins it instead. Either way the row is named by tools/resolve.py, so every entry goes through the contention rule, names.txt and the stickiness rule below.

always.txt and names.txt accept the same spellings, since both key on a repository: a line copied out of manual.txt reaches the row it names, and a ref on it is ignored. The exception is a git+https:// reference, whose owner comes out of the url path — write that one as owner/repo in those two files. A line neither parser can key is warned about on the next run rather than sitting there doing nothing.

A flake listed here is also exempt from tools/classify.py, which guesses from the repository name which flakes are somebody's own machine configuration. catppuccin/nix is a theme, but its repository is named nix, which is exactly the shape of the personal configs the rule exists to drop, and a hand-written line is better evidence than the name. So manual.txt means "index this, whatever the pipeline concludes on its own", and blocklist.txt below is its opposite: reach for manual.txt when search cannot see a repository or when the classifier is wrong about one.

To add a flake, add a line to manual.txt and regenerate:

$ nix run .#update -- --no-harvest

The new flake is fetched once by nix flake metadata, its locked attributes are written to pins.jsonl, and index.json gains an entry.

resolved.jsonl and pins.jsonl are not committed. Cut a release for the bytes they now hold, which repoints data-pins.json:

$ nix run .#cut-data-release

Then commit manual.txt, data-pins.json, index.json and any new file under locks/.

The check workflow regenerates the index on every pull request and fails if the committed index.json differs from the generated one. It also re-derives every pin the pull request adds or changes with nix flake metadata and evaluates every new name, so the committed locked attributes are checked against what the source really serves. The same check runs locally with nix run .#verify.

Removing

Add the attribute name to blocklist.txt, one per line, and regenerate:

some-flake

The row stays in resolved.jsonl, so the name stays reserved; the flake is no longer indexed. Flakes that fail to pin do not need an entry: tools/pin.py records them in failures.jsonl with the error.

Refresh cadence

Each run re-resolves the 2,000 rows resolved longest ago, so with about 16,000 flakes a given one comes round roughly every eight days. always.txt is the exemption: one repository per line, re-resolved on every run however recently it was last looked at.

NixOS/nixpkgs
nix-community/home-manager

Use it for a flake whose pin someone would notice going stale — the five foundations, whose revision is substituted into every indexed flake, and the handful people track daily. A line here does not consume the rolling window's budget, so nothing else is refreshed less often, and tools/pin.py is keyed by revision, so on a day the flake did not move it costs one lookup. Keep the list short anyway: the rolling window already covers anything that is not moving fast, and a line for a repository that is not in resolved.jsonl does nothing.

Names

An attribute name is derived from the repository name, and a bare name is only assigned when one repository claims it. Sixty-one repositories are named home-manager and 110 are named flake; a name several of them could equally mean identifies none of them, so a contested name goes to nobody and every claimant gets the owner appended: home-manager-rc-14.

names.txt is where a person says which repository a name means. One entry per line, the repository then the name:

nix-community/home-manager  home-manager
nixified-ai/flake           nixified-ai

That does two jobs. It hands a contested name to the project people mean when they type it, which is the only way home-manager or nixpkgs gets a bare name at all. And it replaces a derived name that says nothing: nixified-ai/flake derives flake and catppuccin/nix derives nix.

A name of - is the third job, and it takes a bare name away:

akirak/git-hooks  -

akirak/git-hooks is then named git-hooks-akirak and nothing holds git-hooks. Reach for that when one repository holds a name people overwhelmingly use for a different project, which matters beyond the attribute: an index name is what unified substitutes on, so a bare name on the wrong repository rewrites that input for every flake declaring it. 319 indexed flakes declare git-hooks and mean cachix/git-hooks.nix.

Leaving a contested repository out is the normal case. It stays reachable by its qualified name, and a bare name is reserved only when it carries real information: postgres does not obviously mean supabase/postgres.

A name never changes once assigned, because consumers refer to flakes by name — a repository that later gains stars does not take a bare name from the one holding it. A names.txt line is the only thing that outranks that, and it applies on the next run rather than whenever the row next comes round for a refresh: the repository the line names takes the name, and whoever was holding it is displaced to its qualified form.

Sorted lists

manual.txt, blocklist.txt, always.txt and names.txt are all sorted by keep-sorted. Each group of entries is its own block, between a # keep-sorted start case=no line and a # keep-sorted end line, so a group keeps the comment that says why its lines are there and is still sorted within itself:

# The five foundations. Their revision is substituted into every indexed
# flake, so these are the pins with the widest reach.
# keep-sorted start case=no
hercules-ci/flake-parts
nix-systems/default
NixOS/flake-compat
NixOS/nixpkgs
numtide/flake-utils
# keep-sorted end

Add a line anywhere inside the block that fits it and run nix fmt, which sorts it into place. nix flake check fails on a block left unsorted. The markers are comments, so every tool that reads these files ignores them. case=no sorts the way a reader reads: GitHub is case-insensitive about owners, and case-sensitive order would file every NixOS/ line ahead of every lowercase one.

Edit this page on GitHub