From a2d119e73b278a662d7a1f2c1052509ca0c2c5fb Mon Sep 17 00:00:00 2001 From: Harry Hornbacher Date: Thu, 6 Aug 2026 12:58:55 +0200 Subject: [PATCH] add a nix flake for building and installing faff - build with rustPlatform.buildRustPackage using the vendored Cargo.lock - wrap the binary so jj and wezterm are on PATH at runtime; claude still comes from the interactive session (spawned inside a wezterm pane) - skip the jj-dependent test suite in the sandboxed build - expose packages.default, apps.default, and a dev shell with the rust toolchain + jj + wezterm - read name and version from Cargo.toml - document nix usage in the README --- .gitignore | 1 + README.md | 15 +++++++++++ flake.lock | 61 +++++++++++++++++++++++++++++++++++++++++ flake.nix | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.gitignore b/.gitignore index d81f12e..8807164 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /.idea +/result diff --git a/README.md b/README.md index 999fb8e..200de90 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,21 @@ cargo test # 115 tests; the workspace integration tests shell out t cargo clippy --all-targets ``` +## Nix + +A flake is provided. It builds faff and wraps the binary so `jj` and `wezterm` are on +`PATH` at runtime (`claude` still comes from your interactive session, since faff spawns it +inside a WezTerm pane). + +```sh +nix run github:Jezza/faff # run without installing +nix profile install github:Jezza/faff # install into your profile +nix develop # dev shell with the toolchain + jj + wezterm +``` + +To install declaratively, add the flake as an input and reference +`faff.packages.${system}.default`. + ## Usage From your repo root, inside WezTerm: diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..5825cc2 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1785967620, + "narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..e9d918d --- /dev/null +++ b/flake.nix @@ -0,0 +1,79 @@ +{ + description = "faff — a TUI for running several Claude Code agents in parallel on one repo"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { + self, + nixpkgs, + flake-utils, + }: + flake-utils.lib.eachDefaultSystem ( + system: let + pkgs = import nixpkgs {inherit system;}; + + # Runtime dependencies faff shells out to by bare name. jj drives the + # workspaces and wezterm drives the panes. `claude` is intentionally NOT + # here: faff spawns it via `wezterm cli spawn -- claude ...`, so it runs + # in the user's interactive shell inside the pane, not from faff's PATH. + runtimeDeps = [ + pkgs.jujutsu # provides `jj` + pkgs.wezterm # provides `wezterm` + ]; + + cargoToml = pkgs.lib.importTOML ./Cargo.toml; + + faff = pkgs.rustPlatform.buildRustPackage { + pname = cargoToml.package.name; + version = cargoToml.package.version; + + src = self; + + cargoLock.lockFile = ./Cargo.lock; + + nativeBuildInputs = [pkgs.makeWrapper]; + + # rusqlite's `bundled` feature compiles SQLite from C; the stdenv cc + # covers that, no extra buildInputs needed. + + # The test suite (115 tests) shells out to a real `jj`, which is not + # available in the build sandbox, so skip it during the Nix build. + doCheck = false; + + postInstall = '' + wrapProgram $out/bin/faff \ + --prefix PATH : ${pkgs.lib.makeBinPath runtimeDeps} + ''; + + meta = { + description = "TUI for running several Claude Code agents in parallel on one repo, each in its own jj workspace and WezTerm pane"; + homepage = "https://github.com/Jezza/faff"; + mainProgram = "faff"; + }; + }; + in { + packages.default = faff; + packages.faff = faff; + + apps.default = { + type = "app"; + program = "${faff}/bin/faff"; + }; + + devShells.default = pkgs.mkShell { + inputsFrom = [faff]; + packages = + runtimeDeps + ++ [ + pkgs.cargo + pkgs.rustc + pkgs.clippy + pkgs.rustfmt + ]; + }; + } + ); +}