with one click
uv2nix
uv2nix Skill
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
uv2nix Skill
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Read, write, search and reorganise notes in the local Obsidian vaults. Use for anything touching ~/Documents/R3_vault, ~/Documents/Synechron or ~/Documents/My_Obsidian_Vault/Privat — finding notes, adding or editing content, renaming/moving notes without breaking links, and daily notes. Triggers on "my notes", "my vault", "Obsidian", "write this up in my notes", or a request to look something up in personal documentation.
Manage DNS records for the user's GoDaddy-registered domains. Add/upsert, delete, list, look up specific records, verify a stored record matches an expected value, and check public DNS resolution via dig. Triggers on `/dns`, requests to add/change/check A, AAAA, CNAME, MX, TXT, NS, SRV records on the user's domains, debugging DNS propagation, or auditing what's set at GoDaddy vs what's resolving in the wild.
Operate Google Workspace from the terminal via the `gog` CLI (gogcli). Use for checking and replying to Gmail, managing Google Tasks, reading and creating Calendar events, Google Chat (spaces/DMs/messages), Meet spaces, Contacts, Drive/Docs/Sheets, and more. Triggers on `/gog`, `/gog mail`, `/gog tasks`, `/gog events`, `/gog chat`, `/gog meet`, or any request to check/read/reply/send email, list or add tasks, see today's agenda, or message someone on Chat for the user's Google account.
Agenix Skill
cargo2nix Skill
COSMIC Desktop Environment Skill
| name | uv2nix |
| version | 1 |
| description | uv2nix Skill |
A specialized skill for converting Python projects using uv to Nix expressions, enabling declarative and reproducible Python package management with Nix.
Purpose: Provide comprehensive support for using uv2nix to generate Nix derivations from uv workspaces, manage Python dependencies, and integrate Python projects with Nix/NixOS.
Invoke When:
uv2nix takes a uv workspace and generates Nix derivations dynamically using pure Nix code. It bridges the gap between uv (Astral's fast Python package manager) and Nix.
Key Benefits:
Built on pyproject.nix:
# Via curl
curl -LsSf https://astral.sh/uv/install.sh | sh
# Via nix
nix-env -iA nixpkgs.uv
# Or in NixOS configuration
environment.systemPackages = [ pkgs.uv ];
# Via nix
nix-env -f '<nixpkgs>' -iA uv2nix
# Or from flake
nix profile install github:pyproject-nix/uv2nix
# Verify
uv2nix --version
# /etc/nixos/configuration.nix
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
uv
uv2nix
];
}
home.packages = with pkgs; [
uv
uv2nix
];
# Create new Python project with uv
uv init my-python-app
cd my-python-app
# Add dependencies
uv add requests flask
# Generate lock file
uv lock
# Project structure:
# my-python-app/
# ├── pyproject.toml
# ├── uv.lock
# └── src/
# └── my_python_app/
# └── __init__.py
# Generate Nix derivations from uv workspace
uv2nix
# This creates/updates:
# - default.nix (or checks flake.nix)
# - Nix expressions for the workspace
# Build the package
nix-build
# Or with flakes
nix build
# Run the application
./result/bin/my-python-app
pyproject.toml - Project metadata:
[project]
name = "my-python-app"
version = "0.1.0"
description = "My Python application"
requires-python = ">=3.11"
dependencies = [
"requests>=2.31.0",
"flask>=3.0.0",
]
[project.scripts]
my-app = "my_python_app.main:main"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.uv]
dev-dependencies = [
"pytest>=7.4.0",
"black>=23.0.0",
"ruff>=0.1.0",
]
uv.lock - Lock file with pinned versions:
# Generated by uv
# Contains exact dependency versions
# Should be committed to version control
# Create workspace
mkdir my-workspace
cd my-workspace
# Initialize workspace
cat > pyproject.toml <<EOF
[tool.uv.workspace]
members = ["packages/*"]
EOF
# Create packages
mkdir -p packages/lib packages/app
# Package 1: Library
cd packages/lib
uv init
cat > pyproject.toml <<EOF
[project]
name = "my-lib"
version = "0.1.0"
EOF
# Package 2: Application
cd ../app
uv init
cat > pyproject.toml <<EOF
[project]
name = "my-app"
version = "0.1.0"
dependencies = ["my-lib"]
EOF
cd ../..
uv lock
# At workspace root
uv2nix
# Generates derivations for all workspace members
{
description = "My Python application using uv2nix";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
pyproject-nix = {
url = "github:pyproject-nix/pyproject.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
uv2nix = {
url = "github:pyproject-nix/uv2nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.pyproject-nix.follows = "pyproject-nix";
};
};
outputs = { self, nixpkgs, pyproject-nix, uv2nix }:
let
forAllSystems = nixpkgs.lib.genAttrs [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
in
{
packages = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
# Load workspace
workspace = uv2nix.lib.${system}.loadWorkspace { workspaceRoot = ./.; };
# Create Python environment
pythonSet = pkgs.callPackage pyproject-nix.build.packages {
python = pkgs.python311;
};
# Build application
app = pythonSet.mkPyprojectApplication {
inherit workspace;
};
in
{
default = app;
my-python-app = app;
}
);
devShells = forAllSystems (system:
let
pkgs = nixpkgs.legacyPackages.${system};
workspace = uv2nix.lib.${system}.loadWorkspace { workspaceRoot = ./.; };
pythonEnv = pkgs.python311.withPackages (ps:
uv2nix.lib.${system}.getWorkspacePackages workspace ps
);
in
{
default = pkgs.mkShell {
packages = [
pythonEnv
pkgs.uv
];
shellHook = ''
echo "Python development environment"
echo "Python: $(python --version)"
echo "uv: $(uv --version)"
'';
};
}
);
apps = forAllSystems (system: {
default = {
type = "app";
program = "${self.packages.${system}.default}/bin/my-app";
};
});
};
}
Usage:
# Build
nix build
# Run
nix run
# Development shell
nix develop
# Update dependencies
uv lock
nix flake lock --update-input uv2nix
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
let
# Load uv2nix
uv2nix = pkgs.callPackage (pkgs.fetchFromGitHub {
owner = "pyproject-nix";
repo = "uv2nix";
rev = "main";
sha256 = "...";
}) {};
workspace = uv2nix.lib.loadWorkspace { workspaceRoot = ./.; };
pythonEnv = pkgs.python311.withPackages (ps:
uv2nix.lib.getWorkspacePackages workspace ps
);
in
pkgs.mkShell {
packages = [
pythonEnv
pkgs.uv
pkgs.ruff
pkgs.black
];
shellHook = ''
echo "Python development environment ready"
python --version
'';
}
{ pkgs ? import <nixpkgs> {} }:
let
workspace = /* load workspace */;
pythonEnv = /* create environment */;
in
pkgs.mkShell {
packages = [
pythonEnv
pkgs.uv
# Linting and formatting
pkgs.ruff
pkgs.black
pkgs.mypy
# Testing
pkgs.python311Packages.pytest
pkgs.python311Packages.pytest-cov
# Development tools
pkgs.python311Packages.ipython
pkgs.python311Packages.ipdb
];
shellHook = ''
# Set up development environment
export PYTHONPATH="$PWD/src:$PYTHONPATH"
export UV_CACHE_DIR="$PWD/.uv-cache"
# Create virtual environment if needed
if [ ! -d .venv ]; then
uv venv
fi
source .venv/bin/activate
echo "🐍 Python development environment"
echo "Python: $(python --version)"
echo "uv: $(uv --version)"
echo ""
echo "Available commands:"
echo " uv add <package> - Add dependency"
echo " uv lock - Update lock file"
echo " pytest - Run tests"
echo " ruff check . - Lint code"
echo " black . - Format code"
'';
}
# pyproject.toml
[project]
name = "my-cli"
version = "1.0.0"
description = "My CLI tool"
[project.scripts]
my-cli = "my_cli.main:cli"
dependencies = [
"click>=8.0.0",
"rich>=13.0.0",
]
Build with Nix:
{ pkgs, workspace }:
pkgs.python311Packages.buildPythonApplication {
pname = "my-cli";
version = "1.0.0";
src = ./.;
propagatedBuildInputs = with pkgs.python311Packages; [
click
rich
];
# From workspace
pyproject = true;
meta = {
description = "My CLI tool";
license = pkgs.lib.licenses.mit;
mainProgram = "my-cli";
};
}
[project]
name = "my-webapp"
version = "1.0.0"
dependencies = [
"flask>=3.0.0",
"gunicorn>=21.0.0",
]
[project.scripts]
my-webapp = "my_webapp.app:main"
NixOS Service:
{ config, lib, pkgs, ... }:
let
myWebapp = /* build from uv2nix */;
in
{
systemd.services.my-webapp = {
description = "My Python Web Application";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${myWebapp}/bin/gunicorn -b 0.0.0.0:8000 my_webapp.app:app";
Restart = "on-failure";
DynamicUser = true;
# Security hardening
ProtectSystem = "strict";
NoNewPrivileges = true;
PrivateTmp = true;
};
environment = {
PYTHONUNBUFFERED = "1";
FLASK_ENV = "production";
};
};
networking.firewall.allowedTCPPorts = [ 8000 ];
}
# pyproject.toml
[tool.uv]
dev-dependencies = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-asyncio>=0.21.0",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
{ pkgs, workspace }:
let
pythonEnv = /* build environment with dev deps */;
in
pkgs.stdenv.mkDerivation {
name = "my-app-tests";
src = ./.;
buildInputs = [ pythonEnv ];
checkPhase = ''
pytest tests/ -v --cov=src
'';
installPhase = ''
mkdir -p $out
echo "Tests passed" > $out/result
'';
}
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cachix/install-nix-action@v22
- uses: cachix/cachix-action@v12
with:
name: pyproject-nix
- run: nix build .#checks.x86_64-linux.default
# overlay.nix
final: prev: {
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
(python-final: python-prev: {
my-package = python-final.buildPythonPackage {
pname = "my-package";
version = "1.0.0";
src = ./.;
propagatedBuildInputs = with python-final; [
requests
flask
];
pyproject = true;
};
})
];
}
{ pkgs ? import <nixpkgs> {
overlays = [ (import ./overlay.nix) ];
}
}:
{
my-app = pkgs.python311Packages.my-package;
}
# Create project
uv init my-package
cd my-package
# Add dependencies
uv add requests click
# Lock dependencies
uv lock
# Generate Nix expressions
uv2nix
# Build
nix-build
# Install
nix-env -f default.nix -iA package
# pyproject.toml
[project]
name = "my-lib"
version = "0.1.0"
description = "My Python library"
dependencies = [
"numpy>=1.24.0",
"pandas>=2.0.0",
]
[build-system]
requires = ["setuptools>=68.0"]
build-backend = "setuptools.build_meta"
# Initialize with scientific packages
uv init data-analysis
cd data-analysis
uv add numpy pandas matplotlib scipy jupyter
# Lock
uv lock
# Generate Nix with development deps
# shell.nix for data science
{ pkgs ? import <nixpkgs> {} }:
let
pythonEnv = pkgs.python311.withPackages (ps: with ps; [
numpy
pandas
matplotlib
scipy
jupyter
ipython
scikit-learn
]);
in
pkgs.mkShell {
packages = [
pythonEnv
pkgs.uv
];
shellHook = ''
jupyter notebook
'';
}
[project]
name = "my-api"
version = "1.0.0"
dependencies = [
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"pydantic>=2.0.0",
]
[project.scripts]
my-api = "my_api.main:run"
NixOS Service:
systemd.services.my-api = {
serviceConfig = {
ExecStart = "${myApi}/bin/uvicorn my_api.main:app --host 0.0.0.0 --port 8000";
DynamicUser = true;
};
};
uv init my-django-app
cd my-django-app
uv add django psycopg2-binary gunicorn
# Lock
uv lock
# NixOS module
{ config, pkgs, ... }:
let
djangoApp = /* build with uv2nix */;
in
{
services.postgresql = {
enable = true;
ensureDatabases = [ "myapp" ];
};
systemd.services.django = {
serviceConfig = {
ExecStart = "${djangoApp}/bin/gunicorn myapp.wsgi:application";
Environment = [
"DJANGO_SETTINGS_MODULE=myapp.settings"
"DATABASE_URL=postgresql:///myapp"
];
};
};
}
# Add runtime dependency
uv add requests
# Add with version constraint
uv add "flask>=3.0.0,<4.0.0"
# Add development dependency
uv add --dev pytest black ruff
# Add optional dependency group
uv add --group docs sphinx sphinx-rtd-theme
# Lock after changes
uv lock
# Remove dependency
uv remove requests
# Lock
uv lock
# Update all dependencies
uv lock --upgrade
# Update specific package
uv lock --upgrade-package requests
# Check outdated
uv pip list --outdated
# /etc/nixos/configuration.nix
{ config, pkgs, ... }:
let
myPythonApp = import /path/to/app {
inherit pkgs;
};
in
{
environment.systemPackages = [
myPythonApp
];
}
# home.nix
{ pkgs, ... }:
let
myTool = import /path/to/tool {
inherit pkgs;
};
in
{
home.packages = [
myTool
];
}
# modules/my-python-service.nix
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.my-python-service;
myApp = import ../python-app {
inherit pkgs;
};
in
{
options.services.my-python-service = {
enable = mkEnableOption "My Python Service";
port = mkOption {
type = types.int;
default = 8000;
};
workers = mkOption {
type = types.int;
default = 4;
};
};
config = mkIf cfg.enable {
systemd.services.my-python-service = {
description = "My Python Service";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${myApp}/bin/gunicorn \
-w ${toString cfg.workers} \
-b 0.0.0.0:${toString cfg.port} \
app:application
'';
Restart = "on-failure";
DynamicUser = true;
};
};
networking.firewall.allowedTCPPorts = [ cfg.port ];
};
}
Problem: Changes to pyproject.toml not reflected
Solution:
# Regenerate lock file
uv lock
# Force update
uv lock --upgrade
# Regenerate Nix expressions
uv2nix
Problem: Package fails to build with Nix
Solution:
# Add missing build dependencies
{ pkgs, ... }:
pkgs.python311Packages.buildPythonPackage {
# ...
nativeBuildInputs = with pkgs; [
python311Packages.setuptools
python311Packages.wheel
];
buildInputs = with pkgs; [
# System dependencies
gcc
pkg-config
openssl
];
}
Problem: Module not found at runtime
Solution:
# Ensure proper Python path
{
shellHook = ''
export PYTHONPATH="$PWD/src:$PYTHONPATH"
'';
}
Problem: Package with C extensions fails
Solution:
# Ensure build tools in environment
buildInputs = with pkgs; [
python311Packages.setuptools
gcc
python311.pkgs.cython
];
Problem: Workspace packages not found
Solution:
# Ensure proper workspace structure
# pyproject.toml at root with:
[tool.uv.workspace]
members = ["packages/*"]
# Regenerate
uv lock
uv2nix
Always commit lock files
git add uv.lock
git commit -m "Lock dependencies"
Use PEP-621 pyproject.toml
[project]
name = "my-package"
version = "0.1.0"
requires-python = ">=3.11"
Pin Python version
[project]
requires-python = ">=3.11,<3.12"
Version control Nix expressions
git add default.nix flake.nix
Use development dependencies
uv add --dev pytest ruff black
Test in clean environment
nix-build
./result/bin/my-app
Document dependencies
[project]
dependencies = [
"requests>=2.31.0", # HTTP client
"click>=8.0.0", # CLI framework
]
Use flakes for reproducibility
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
Leverage workspace features
[tool.uv.workspace]
members = ["packages/*"]
Keep uv and uv2nix updated
uv self update
nix profile upgrade uv2nix
Don't commitpycache
__pycache__/
*.pyc
Don't skip lock file
# ❌ Bad
uv add requests # without uv lock
# ✅ Good
uv add requests && uv lock
Don't mix pip and uv
# ❌ Don't use pip install with uv project
# ✅ Use uv add
Don't hardcode paths
# ❌ Bad
config_path = "/home/user/config.json"
# ✅ Good
config_path = os.path.expanduser("~/.config/myapp/config.json")
Don't commit secrets
# Use environment variables or secret management
# Never commit API keys, passwords
Don't skip tests
# Always run tests before committing
pytest tests/
Don't ignore warnings
# Address deprecation warnings
# Fix type errors
# uv commands
uv init [project] # Initialize project
uv add <package> # Add dependency
uv add --dev <package> # Add dev dependency
uv remove <package> # Remove dependency
uv lock # Generate lock file
uv lock --upgrade # Update all dependencies
uv sync # Install dependencies
uv run <command> # Run in environment
uv tree # Show dependency tree
# uv2nix commands
uv2nix # Generate Nix expressions
uv2nix --help # Show help
# Nix commands
nix-build # Build package
nix-shell # Enter dev environment
nix flake init # Initialize flake
nix build # Build (flakes)
nix develop # Dev shell (flakes)
nix run # Run app (flakes)
Ready to build reproducible Python applications with uv2nix! 🐍