---
title: "Tooling"
description: "Formatter, prek, pinned third-party binaries, and the language toolchains."
---

# 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`](https://prek.j178.dev) (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`.

```sh
# 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`](../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`](https://github.com/Mic92/nix-update) (installed via `home.nix`) to find and update them in place:

```sh
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`](https://github.com/Comamoca/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](https://github.com/r-lib/rig).

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

```sh
# 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`](https://github.com/astral-sh/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`](https://github.com/unclebob/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.

```sh
# 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:

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

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