Search Documentation

Search for pages and headings in the documentation

Tooling

This page covers the developer tooling and package-management details of the configuration.

Flake formatter

flake.nix exposes a formatter output (nixfmt-tree, a treefmt wrapper around the official nixfmt) so you can run nix fmt <file>.nix on any Nix file, or nix fmt . on the whole tree. The Justfile provides just fmt.

prek

prek.toml configures prek (a Rust reimplementation of pre-commit) with local hooks that run:

  • nix fmt on staged Nix files.
  • rumdl check on staged Markdown and MDX files (including the docs/*.mdx sources of the docs site).
  • shellcheck on staged shell scripts.
  • bun test on JavaScript/TypeScript changes (from pi-extensions/).

prek itself is installed via home.nix.

# install the git pre-commit hook
prek install

# run all hooks on all files
prek run -a

Updating pinned third-party binaries

Some tools are not pulled from nixpkgs but pinned directly as fetchurl/fetchFromGitHub derivations in pkgs/default.nix, so nix flake update does not bump them. These packages are re-exported from the flake as packages.<system>.<name> for aarch64-darwin, x86_64-linux, and aarch64-linux.

This structure allows nix-update (installed via home.nix) to find and update them in place:

nix-update --flake filen-cli
nix-update --flake git-sv
nix-update --flake jarl
nix-update --flake arf

These packages select the appropriate prebuilt binaries per host platform. After any bump, run home-manager switch --flake .#philipp (macOS) or home-manager switch --flake .#philipp-linux (Linux) to activate.

Swift toolchain

modules/swift.nix installs an official Swift toolchain (swiftc, SwiftPM, sourcekit-lsp, swift-format) from the swift-overlay flake input, which repackages the prebuilt swift.org releases for aarch64-darwin and x86_64-linux. Swift is not taken from nixpkgs because nixpkgs builds it from source and lags swift.org: the pinned nixpkgs ships 6.2.4 and nixpkgs HEAD only reaches 6.3.3, while this setup pins the current 6.4.1. The release is selected by the swiftVersion string at the top of the module, and the release table and hashes come from the swift-overlay input, both pinned by flake.lock. Move Swift with nix flake update swift-overlay to refresh the release table, bump swiftVersion in modules/swift.nix, and run just switch.

R Installation Manager (rig)

rig is a custom package for managing R versions on macOS only (pkgs/rig/default.nix). It downloads the official macOS arm64 .pkg installer from GitHub, as rig provides no Linux binaries.

  • Version: 0.8.0.
  • Platform: aarch64-darwin.
  • Source: r-lib/rig.

Since rig requires system-wide installation via the macOS .pkg format:

# after home-manager activation, install rig system-wide
sudo installer -pkg "$(dirname "$(which rig)")/rig-0.8.0-macOS-arm64.pkg" -target /

# then use rig to manage R versions
rig add release  # install the latest R release
rig list         # list installed R versions
rig switch 4.3   # switch to R 4.3

uv-managed Python tools

modules/python.nix manages Python CLI tools via uv instead of nixpkgs, so versions are pinned independently of the nixpkgs release cycle.

  • uv itself comes from nixpkgs, but the CLI tools it manages live outside the Nix store under $XDG_DATA_HOME/uv/tools (i.e. ~/.local/share/uv/tools), with a stable bin directory at .../uv/tool-bin.
  • Versions are pinned in the uvTools attrset at the top of the module (currently ruff and pixelrag).
  • Bumping a version triggers an idempotent reinstall on the next home-manager switch via a per-tool marker file (.hm-version).
  • home.sessionVariables and home.sessionPath only land in hm-session-vars.sh, sourced by login shells. To cover non-login and non-interactive shells, the module re-exports the UV_* vars and prepends tool-bin to PATH via programs.zsh.envExtra.

ub-mode quality gates and Clojure

The ub-mode skill ships with its four companion tools, which are the deterministic quality gates the skill tells an agent to run. All four upstream repos tag no releases, so each is pinned by commit and hash rather than through nix-update.

Tool What it does Package
crapper Cyclomatic complexity, coverage and CRAP scores per function (Clojure, Java, Go, TypeScript, Rust, Python). pkgs/crapper
dryer Structural duplication scores. pkgs/dryer
mutator Mutation testing; reads its function names from crapper. pkgs/mutator
uml-viewer Quil/Processing viewer for the namespace tree with the .metrics/ snapshots overlaid. pkgs/uml-viewer
  • modules/ub-tools.nix puts the four tools on PATH.
  • modules/clojure.nix provides the Clojure CLI and JDK 21 that uml-viewer needs (there was no Clojure module before).
  • The skill itself (modules/ai.nix) is pinned as a fetchurl of upstream’s SKILL.md and shipped verbatim, because the upstream file already carries the frontmatter pi reads. pi-agent/skills/ub-mode/PROVENANCE.md records the source, the pin and the missing upstream licence.
  • pkgs/uml-viewer installs two wrappers, uml-viewer (the :run entry point) and uml-viewer-ir (the :ir policy generator). Both run against the project in the current directory and resolve quil and the Clojure runtime from Maven Central on first use, exactly as upstream’s ./uml launcher does, so the first run needs network access.
# CRAP scores and complexity for the current project (no coverage run)
crapper --no-coverage

# structural duplication
dryer

# list mutation sites without running tests
mutator --scan src

# write the UML IR from a policy, then view it
uml-viewer-ir examples/myproject.policy.edn
uml-viewer examples/myproject.edn

Bump the pins with scripts/bump-ub-tools.sh (all four tools, or one by name) and the skill with scripts/bump-ub-mode-skill.sh.

nix-direnv

modules/dev-tools.nix enables nix-direnv for an improved nix-shell experience and automatic loading of per-project environments in zsh. In a project directory:

# for a nix-shell based project
echo 'use nix' > .envrc && direnv allow

# for a flake-based project
echo 'use flake' > .envrc && direnv allow