7.8 KiB
repo-lib Consumer API
Detect the repo shape
Look for one of these patterns in the consuming repo:
repo-lib.lib.mkReporepo-lib.lib.mkReleaseinputs.repo-lib
Prefer editing the existing style instead of migrating incidentally.
Preferred mkRepo shape
repo-lib.lib.mkRepo {
inherit self nixpkgs;
src = ./.;
systems = repo-lib.lib.systems.default; # optional
config = {
includeStandardPackages = true;
shell = {
env = { };
extraShellText = "";
allowImpureBootstrap = false;
bootstrap = "";
banner = { };
};
formatting = {
programs = { };
settings = { };
};
checks = { };
lefthook = { };
release = null; # or attrset below
};
perSystem = { pkgs, system, lib, config }: {
tools = [ ];
shell.packages = [ ];
checks = { };
lefthook = { };
packages = { };
apps = { };
};
}
Generated outputs:
devShells.${system}.defaultchecks.${system}.formatting-checkchecks.${system}.hook-checkchecks.${system}.lefthook-checkformatter.${system}packages.${system}.releasewhenconfig.release != null- merged
packagesandappsfromperSystem
Merge points:
config.checksmerges withperSystem.checksconfig.lefthookrecursively merges withperSystem.lefthookconfig.shellrecursively merges withperSystem.shell- generated release packages merge with
perSystem.packages
Conflicts on checks, packages, and apps names throw.
config.includeStandardPackages
Default: true
When enabled, the shell includes:
nixfmtgitlintgitleaksshfmt
Use false only when the consumer explicitly wants to own the full shell package list.
config.shell
Fields:
envAttrset of environment variables exported in the shell.extraShellTextExtra shell snippet appended after the banner.bootstrapShell snippet that runs before the banner.allowImpureBootstrapMust betruewhenbootstrapis non-empty.bannerShell banner configuration.
Rules:
- Default is pure-first.
- Do not add bootstrap work unless the user actually wants imperative local setup.
- The template uses bootstrap intentionally for Bun global install paths and Moon bootstrapping; do not generalize that into normal package setup unless the repo already wants that behavior.
config.shell.banner
Defaults:
{
style = "simple";
icon = "🚀";
title = "Dev shell ready";
titleColor = "GREEN";
subtitle = "";
subtitleColor = "GRAY";
borderColor = "BLUE";
}
Rules:
stylemust besimpleorpretty.borderColormatters only forpretty.- Tool rows can also set
banner.color,banner.icon, andbanner.iconColor. - Required tool probe failures abort shell startup.
config.formatting
Fields:
programsPassed totreefmt-nix.lib.evalModule.settingsPassed tosettings.formatter.
Rules:
nixfmtis always enabled.- Use formatter settings instead of shell hooks for formatting behavior.
Checks
config.checks.<name> and perSystem.checks.<name> use this shape:
{
command = "bun test";
stage = "pre-push"; # or "pre-commit"
passFilenames = false;
runtimeInputs = [ pkgs.bun ];
}
Defaults:
stage = "pre-commit"passFilenames = falseruntimeInputs = [ ]
Rules:
- Only
pre-commitandpre-pushare supported here. - The command is wrapped with
writeShellApplication. pre-commitandpre-pushstages are configured to run in parallel.passFilenames = truemaps to{staged_files}forpre-commitand{push_files}forpre-push.
Raw Lefthook config
Use config.lefthook or perSystem.lefthook when the task needs advanced Lefthook features or unsupported stages.
Pass-through attrset example:
{
checks.tests = {
command = "bun test";
stage = "pre-push";
runtimeInputs = [ pkgs.bun ];
};
lefthook.pre-push.commands.tests.stage_fixed = true;
lefthook.commit-msg.commands.commitlint = {
run = "bun commitlint --edit {1}";
stage_fixed = true;
};
}
Structured hook-entry example in a raw hook list:
perSystem = { pkgs, ... }: {
lefthook.biome = {
entry = "${pkgs.biome}/bin/biome check";
pass_filenames = true;
stages = [ "pre-commit" "pre-push" ];
};
};
Rules:
config.lefthookandperSystem.lefthookare recursive attrset passthroughs merged after generated checks.- Structured hook entries support only:
description,enable,entry,name,package,pass_filenames,stages stagesmay includepre-commit,pre-push, orcommit-msg.pass_filenames = truemaps to{1}forcommit-msg.
Tools
Preferred shape in perSystem.tools:
(repo-lib.lib.tools.fromPackage {
name = "Bun";
package = pkgs.bun;
version = {
args = [ "--version" ];
match = null;
regex = null;
group = 0;
line = 1;
};
banner = {
color = "YELLOW";
icon = "";
iconColor = null;
};
required = true;
})
For a tool that should come from the host PATH instead of nixpkgs:
(repo-lib.lib.tools.fromCommand {
name = "Nix";
command = "nix";
version = {
args = [ "--version" ];
group = 1;
};
})
Helper:
repo-lib.lib.tools.simple "Go" pkgs.go [ "version" ]
Tool behavior:
- Package-backed tools are added to the shell automatically.
- Command-backed tools are probed from the existing
PATHand are not added to the shell automatically. - Banner probing uses the resolved executable path.
required = trueby default.- When
version.matchis set, the first matching output line is selected beforeregexextraction. - Required tool probe failure aborts shell startup.
Use shell.packages instead of tools when:
- the package should be in the shell but not in the banner
- the package is not a CLI tool with a stable version probe
config.release
Shape:
{
channels = [ "alpha" "beta" "rc" "internal" ];
steps = [ ];
postVersion = "";
runtimeInputs = [ ];
}
Defaults:
channels = [ "alpha" "beta" "rc" "internal" ]steps = [ ]postVersion = ""runtimeInputs = [ ]
Set release = null to disable the generated release package.
Release step shapes
writeFile
{
writeFile = {
path = "src/version.ts";
text = ''
export const APP_VERSION = "$FULL_VERSION" as const;
'';
};
}
replace
{
replace = {
path = "README.md";
regex = ''^(version = ")[^"]*(")$'';
replacement = ''\1$FULL_VERSION\2'';
};
}
versionMetaSet
{
versionMetaSet = {
key = "desktop_binary_version_max";
value = "$FULL_VERSION";
};
}
versionMetaUnset
{
versionMetaUnset = {
key = "desktop_unused";
};
}
Rules:
- Current supported step kinds are only
writeFile,replace,versionMetaSet, andversionMetaUnset. - Do not document or implement a
runstep in consumer repos unless the library itself gains that feature.
Release ordering
The generated release command currently does this:
- Require a clean git worktree
- Update
VERSION - Run
release.steps - Run
postVersion - Run
nix fmt git add -A- Commit with
chore(release): <tag> - Tag
- Push branch
- Push tags
Important consequences:
postVersionis before formatting, commit, tag, and push.- There is no true post-tag or post-push hook in current
repo-lib. - The current release runner is opinionated and performs commit, tag, and push as part of the flow.
mkRelease
repo-lib.lib.mkRelease remains available when a repo wants only the release package:
repo-lib.lib.mkRelease {
system = system;
nixpkgsInput = nixpkgs; # optional
channels = [ "alpha" "beta" "rc" "internal" ];
steps = [ ];
postVersion = "";
runtimeInputs = [ ];
}
Use the same release-step rules as config.release.