Skip to content

Commit 6d07242

Browse files
Kohei-Wadaclaude
andauthored
feat(nix): add uv2nix flake for reproducible install and dev shells (#1112)
Package the uv workspace with uv2nix so the CLI/TUI, API server, and MCP server can be built and installed via Nix without touching uv.lock. - packages.{default,taskdog}: venv exposing taskdog / taskdog-server / taskdog-mcp, tagged with meta (mainProgram = taskdog) - apps.{taskdog,taskdog-server,taskdog-mcp}: `nix run` entry points - devShells.default: python313 + uv (impure, matches the Makefile flow); devShells.pure: the Nix-built venv on PATH Install: nix profile install github:Kohei-Wada/taskdog Claude-Session: https://claude.ai/code/session_011tvnMkaZhSWLfm6ne4UEbz Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 1bbfe5d commit 6d07242

2 files changed

Lines changed: 266 additions & 0 deletions

File tree

flake.lock

Lines changed: 99 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
{
2+
description = "Taskdog - individual task management (CLI/TUI + REST API), packaged with uv2nix";
3+
4+
inputs = {
5+
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
6+
7+
pyproject-nix = {
8+
url = "github:pyproject-nix/pyproject.nix";
9+
inputs.nixpkgs.follows = "nixpkgs";
10+
};
11+
12+
uv2nix = {
13+
url = "github:pyproject-nix/uv2nix";
14+
inputs.pyproject-nix.follows = "pyproject-nix";
15+
inputs.nixpkgs.follows = "nixpkgs";
16+
};
17+
18+
pyproject-build-systems = {
19+
url = "github:pyproject-nix/build-system-pkgs";
20+
inputs.pyproject-nix.follows = "pyproject-nix";
21+
inputs.uv2nix.follows = "uv2nix";
22+
inputs.nixpkgs.follows = "nixpkgs";
23+
};
24+
};
25+
26+
outputs =
27+
{
28+
self,
29+
nixpkgs,
30+
uv2nix,
31+
pyproject-nix,
32+
pyproject-build-systems,
33+
...
34+
}:
35+
let
36+
inherit (nixpkgs) lib;
37+
38+
# Load the uv workspace from the repo root (reads pyproject.toml + uv.lock).
39+
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
40+
41+
# Overlay translating the uv.lock into a pyproject.nix package set.
42+
# Prefer wheels — fewer packages need to be compiled from source.
43+
overlay = workspace.mkPyprojectOverlay {
44+
sourcePreference = "wheel";
45+
};
46+
47+
# Project-specific overrides. Empty for now; add entries here if a
48+
# dependency fails to build (e.g. missing native build inputs).
49+
pyprojectOverrides = _final: _prev: { };
50+
51+
# Supported systems.
52+
systems = [
53+
"x86_64-linux"
54+
"aarch64-linux"
55+
"aarch64-darwin"
56+
"x86_64-darwin"
57+
];
58+
forAllSystems = lib.genAttrs systems;
59+
60+
pkgsFor = system: nixpkgs.legacyPackages.${system};
61+
62+
# Match the project's pinned interpreter (.python-version = 3.13).
63+
pythonFor = system: (pkgsFor system).python313;
64+
65+
# Fully-resolved python package set for a given system.
66+
pythonSetFor =
67+
system:
68+
let
69+
pkgs = pkgsFor system;
70+
python = pythonFor system;
71+
in
72+
(pkgs.callPackage pyproject-nix.build.packages {
73+
inherit python;
74+
}).overrideScope
75+
(
76+
lib.composeManyExtensions [
77+
pyproject-build-systems.overlays.default
78+
overlay
79+
pyprojectOverrides
80+
]
81+
);
82+
83+
# A virtualenv containing every workspace package + its runtime deps.
84+
# Tagged with meta so `nix profile install` and `nix run` behave nicely.
85+
venvFor =
86+
system:
87+
((pythonSetFor system).mkVirtualEnv "taskdog-env" workspace.deps.default).overrideAttrs
88+
(old: {
89+
meta = (old.meta or { }) // {
90+
description = "Taskdog - individual task management (CLI/TUI + REST API)";
91+
homepage = "https://github.com/Kohei-Wada/taskdog";
92+
license = lib.licenses.mit;
93+
mainProgram = "taskdog";
94+
platforms = systems;
95+
};
96+
});
97+
in
98+
{
99+
# `nix build` / `nix build .#taskdog` -> a venv exposing the CLI, server, MCP.
100+
# Install with: nix profile install github:Kohei-Wada/taskdog
101+
packages = forAllSystems (
102+
system:
103+
let
104+
venv = venvFor system;
105+
in
106+
{
107+
default = venv;
108+
taskdog = venv;
109+
}
110+
);
111+
112+
# `nix run .#taskdog` (CLI/TUI), `.#taskdog-server`, `.#taskdog-mcp`.
113+
apps = forAllSystems (
114+
system:
115+
let
116+
venv = venvFor system;
117+
in
118+
{
119+
default = self.apps.${system}.taskdog;
120+
taskdog = {
121+
type = "app";
122+
program = "${venv}/bin/taskdog";
123+
};
124+
taskdog-server = {
125+
type = "app";
126+
program = "${venv}/bin/taskdog-server";
127+
};
128+
taskdog-mcp = {
129+
type = "app";
130+
program = "${venv}/bin/taskdog-mcp";
131+
};
132+
}
133+
);
134+
135+
# Dev shells.
136+
devShells = forAllSystems (
137+
system:
138+
let
139+
pkgs = pkgsFor system;
140+
python = pythonFor system;
141+
in
142+
{
143+
# Impure shell: uses uv directly to manage the .venv (editable installs,
144+
# matches the Makefile workflow). Run `uv sync` inside, then `make test`.
145+
default = pkgs.mkShell {
146+
packages = [
147+
python
148+
pkgs.uv
149+
];
150+
env = {
151+
# Force uv to use the nixpkgs interpreter, never download one.
152+
UV_PYTHON_DOWNLOADS = "never";
153+
UV_PYTHON = python.interpreter;
154+
};
155+
shellHook = ''
156+
unset PYTHONPATH
157+
'';
158+
};
159+
160+
# Pure shell: the fully Nix-built venv on PATH, no uv/network needed.
161+
pure = pkgs.mkShell {
162+
packages = [ (venvFor system) ];
163+
};
164+
}
165+
);
166+
};
167+
}

0 commit comments

Comments
 (0)