Nix Flake Initialization Skill
Purpose
Automatically create and configure flake.nix files for projects that don't have them yet, using flake-parts as the base template. The skill detects programming languages used in the project and extends the default devShell with necessary development packages.
When to Activate
- User asks to "create a flake.nix" or "initialize a flake"
- User wants to "set up Nix development environment"
- User mentions "add flake support" or "nix-ify this project"
- User asks to "add direnv" or "create .envrc"
- Project lacks flake.nix and user asks about development setup
Language Detection Strategy
OpenSCAD
Detection criteria:
- Presence of
*.scad files in the project
- File extensions:
.scad
DevShell packages:
openscad-unstable - Latest OpenSCAD version
Python
Detection criteria:
- Presence of
*.py files in the project
- Presence of
requirements.txt, pyproject.toml, or setup.py
DevShell packages:
- If
requirements.txt exists: Parse it and create python3.withPackages including all modules
- If no requirements file: Just include base
python3
Python module extraction:
- Read
requirements.txt line by line
- Extract package names (ignore version specifiers like
==7.4.2)
- Convert package names to nixpkgs Python package names (usually lowercase, replace hyphens with underscores if needed)
Flake Template Structure
Use this base template for all flakes:
{
description = "PROJECT_DESCRIPTION";
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
};
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" ];
perSystem = { config, self', inputs', pkgs, system, ... }: {
devShells.default = pkgs.mkShell {
name = "default-dev-shell";
meta.description = "Default development shell";
packages = with pkgs; [
LANGUAGE_SPECIFIC_PACKAGES
];
};
};
};
}
Implementation Steps
Step 1: Check for Existing Flake
- Use Glob to check if
flake.nix already exists
- If it exists, ask user if they want to modify or skip
- If it doesn't exist, proceed with creation
Step 2: Detect Programming Languages
- Use Glob to search for language-specific files:
**/*.scad for OpenSCAD
**/*.py for Python
- Check for language-specific manifest files:
requirements.txt for Python dependencies
pyproject.toml, setup.py for Python projects
Step 3: Build Package List
Based on detected languages, construct the packages list:
For OpenSCAD:
openscad-unstable
For Python with requirements.txt:
(python3.withPackages (ps: with ps; [ module1 module2 module3 ]))
For Python without requirements:
python3
Step 4: Generate Project Description
- Use the project directory name as a basis
- If there's a README.md, read the first line or title
- Format as: "Development environment for [project-name]"
Step 5: Create flake.nix
- Substitute PROJECT_DESCRIPTION with generated description
- Substitute LANGUAGE_SPECIFIC_PACKAGES with the constructed package list
- Write the file using the Write tool
Step 6: Create .envrc and Update .gitignore
- Always create
.envrc for direnv integration with content: use flake
- IMPORTANT: Ensure
.envrc uses Unix line endings (LF, \n) NOT DOS line endings (CRLF, \r\n)
- Use the Write tool with explicit LF line endings
- The content should be exactly:
use flake\n (with Unix newline)
- Automatically update
.gitignore to include .direnv/ if not already present
- If
.gitignore doesn't exist, create it with .direnv/ entry
- Inform user they need to run
direnv allow to activate
Step 7: Git Staging (If in Git Repo)
- IMPORTANT: Nix flakes require files to be tracked by Git before they can be evaluated
- If project is a git repository, stage the new files BEFORE running
nix flake check:
- Run
git add flake.nix
- Run
git add .envrc
- Run
git add .gitignore (if modified or created)
- After staging, verify with
nix flake check
- Remind user to run
git add flake.lock after first nix flake update
Example Outputs
Example 1: OpenSCAD + Python Project
Detected files:
wifi-card.scad, qrcode-matrix.scad
requirements.txt with qrcode==7.4.2
Generated packages:
packages = with pkgs; [
openscad-unstable
(python3.withPackages (ps: with ps; [ qrcode ]))
];
Example 2: Python-Only Project
Detected files:
main.py, utils.py
requirements.txt with requests==2.31.0 and flask==3.0.0
Generated packages:
packages = with pkgs; [
(python3.withPackages (ps: with ps; [ requests flask ]))
];
Example 3: OpenSCAD-Only Project
Detected files:
model.scad, parts/base.scad
Generated packages:
packages = with pkgs; [
openscad-unstable
];
Important Notes
System Architecture: Default template uses x86_64-linux. Ask user if they need other systems (e.g., aarch64-linux, x86_64-darwin, aarch64-darwin)
nixpkgs Version: Default uses nixos-25.11. User can modify this to nixos-unstable or other channels if needed
Python Package Name Conversion: Most Python packages have the same name in nixpkgs, but some differ:
pillow (PyPI) → pillow (nixpkgs) ✓
beautifulsoup4 (PyPI) → beautifulsoup4 (nixpkgs) ✓
- Package names with hyphens often work as-is
- If a package isn't found, suggest checking nixpkgs or using
buildPythonPackage
Post-Creation Steps: Always inform the user to:
- Files are automatically staged with
git add if in a Git repo
- Run
nix flake check to verify the flake configuration
- Run
nix flake update to generate flake.lock
- Run
direnv allow to activate direnv (or use nix develop manually)
- The
.envrc and .gitignore updates are handled automatically
Git Integration: Automatically stage files if in a git repo:
flake.nix
.envrc
.gitignore (if modified/created)
- Remind user to commit and to add
flake.lock after generation
Line Endings: Always use Unix line endings (LF) for all generated files, especially .envrc. DOS line endings (CRLF) can cause issues with direnv and shell scripts on Unix systems.
Error Handling
- If language detection finds no supported languages, create a minimal flake with empty packages list
- If requirements.txt parsing fails, use
python3.withPackages with an empty list of packages.
- If user's system isn't
x86_64-linux, ask which systems they need
Future Extensions
The skill is designed to be easily extended with additional languages:
- Rust: detect
Cargo.toml, add cargo, rustc
- Node.js: detect
package.json, add nodejs, nodePackages.npm
- Go: detect
go.mod, add go
- Java: detect
pom.xml or build.gradle, add JDK
To extend, add new detection criteria and package mappings following the existing pattern.
1---2name: nix-flake-init3description: Initializes Nix flake.nix files for projects using flake-parts, automatically detecting programming languages (OpenSCAD, Python) and configuring appropriate development shells. Activates when user asks to create, initialize, or add a flake.nix, set up Nix development environment, or add direnv support.4---5
6# Nix Flake Initialization Skill
7
8## Purpose
9Automatically create and configure `flake.nix` files for projects that don't have them yet, using flake-parts as the base template. The skill detects programming languages used in the project and extends the default devShell with necessary development packages.
10
11## When to Activate
12- User asks to "create a flake.nix" or "initialize a flake"
13- User wants to "set up Nix development environment"
14- User mentions "add flake support" or "nix-ify this project"
15- User asks to "add direnv" or "create .envrc"
16- Project lacks flake.nix and user asks about development setup
17
18## Language Detection Strategy
19
20### OpenSCAD
21**Detection criteria:**
22- Presence of `*.scad` files in the project
23- File extensions: `.scad`
24
25**DevShell packages:**
26- `openscad-unstable` - Latest OpenSCAD version
27
28### Python
29**Detection criteria:**
30- Presence of `*.py` files in the project
31- Presence of `requirements.txt`, `pyproject.toml`, or `setup.py`
32
33**DevShell packages:**
34- If `requirements.txt` exists: Parse it and create `python3.withPackages` including all modules
35- If no requirements file: Just include base `python3`
36
37**Python module extraction:**
38- Read `requirements.txt` line by line
39- Extract package names (ignore version specifiers like `==7.4.2`)
40- Convert package names to nixpkgs Python package names (usually lowercase, replace hyphens with underscores if needed)
41
42## Flake Template Structure
43
44Use this base template for all flakes:
45
46```nix
47{
48 description = "PROJECT_DESCRIPTION";
49
50 inputs = {
51 flake-parts.url = "github:hercules-ci/flake-parts";
52 nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
53 };
54
55 outputs = inputs@{ flake-parts, ... }:
56 flake-parts.lib.mkFlake { inherit inputs; } {
57 systems = [ "x86_64-linux" ];
58 perSystem = { config, self', inputs', pkgs, system, ... }: {
59 devShells.default = pkgs.mkShell {
60 name = "default-dev-shell";
61 meta.description = "Default development shell";
62 packages = with pkgs; [
63 LANGUAGE_SPECIFIC_PACKAGES
64 ];
65 };
66 };
67 };
68}
69```
70
71## Implementation Steps
72
73### Step 1: Check for Existing Flake
74- Use Glob to check if `flake.nix` already exists
75- If it exists, ask user if they want to modify or skip
76- If it doesn't exist, proceed with creation
77
78### Step 2: Detect Programming Languages
79- Use Glob to search for language-specific files:
80 - `**/*.scad` for OpenSCAD
81 - `**/*.py` for Python
82- Check for language-specific manifest files:
83 - `requirements.txt` for Python dependencies
84 - `pyproject.toml`, `setup.py` for Python projects
85
86### Step 3: Build Package List
87Based on detected languages, construct the packages list:
88
89**For OpenSCAD:**
90```nix
91openscad-unstable
92```
93
94**For Python with requirements.txt:**
95```nix
96(python3.withPackages (ps: with ps; [ module1 module2 module3 ]))
97```
98
99**For Python without requirements:**
100```nix
101python3
102```
103
104### Step 4: Generate Project Description
105- Use the project directory name as a basis
106- If there's a README.md, read the first line or title
107- Format as: "Development environment for [project-name]"
108
109### Step 5: Create flake.nix
110- Substitute PROJECT_DESCRIPTION with generated description
111- Substitute LANGUAGE_SPECIFIC_PACKAGES with the constructed package list
112- Write the file using the Write tool
113
114### Step 6: Create .envrc and Update .gitignore
115- **Always** create `.envrc` for direnv integration with content: `use flake`
116- **IMPORTANT**: Ensure `.envrc` uses Unix line endings (LF, `\n`) NOT DOS line endings (CRLF, `\r\n`)
117 - Use the Write tool with explicit LF line endings
118 - The content should be exactly: `use flake\n` (with Unix newline)
119- **Automatically** update `.gitignore` to include `.direnv/` if not already present
120- If `.gitignore` doesn't exist, create it with `.direnv/` entry
121- Inform user they need to run `direnv allow` to activate
122
123### Step 7: Git Staging (If in Git Repo)
124- **IMPORTANT**: Nix flakes require files to be tracked by Git before they can be evaluated
125- If project is a git repository, stage the new files BEFORE running `nix flake check`:
126 - Run `git add flake.nix`
127 - Run `git add .envrc`
128 - Run `git add .gitignore` (if modified or created)
129- After staging, verify with `nix flake check`
130- Remind user to run `git add flake.lock` after first `nix flake update`
131
132## Example Outputs
133
134### Example 1: OpenSCAD + Python Project
135
136Detected files:
137- `wifi-card.scad`, `qrcode-matrix.scad`
138- `requirements.txt` with `qrcode==7.4.2`
139
140Generated packages:
141```nix
142packages = with pkgs; [
143 openscad-unstable
144 (python3.withPackages (ps: with ps; [ qrcode ]))
145];
146```
147
148### Example 2: Python-Only Project
149
150Detected files:
151- `main.py`, `utils.py`
152- `requirements.txt` with `requests==2.31.0` and `flask==3.0.0`
153
154Generated packages:
155```nix
156packages = with pkgs; [
157 (python3.withPackages (ps: with ps; [ requests flask ]))
158];
159```
160
161### Example 3: OpenSCAD-Only Project
162
163Detected files:
164- `model.scad`, `parts/base.scad`
165
166Generated packages:
167```nix
168packages = with pkgs; [
169 openscad-unstable
170];
171```
172
173## Important Notes
174
1751. **System Architecture**: Default template uses `x86_64-linux`. Ask user if they need other systems (e.g., `aarch64-linux`, `x86_64-darwin`, `aarch64-darwin`)
176
1772. **nixpkgs Version**: Default uses `nixos-25.11`. User can modify this to `nixos-unstable` or other channels if needed
178
1793. **Python Package Name Conversion**: Most Python packages have the same name in nixpkgs, but some differ:
180 - `pillow` (PyPI) → `pillow` (nixpkgs) ✓
181 - `beautifulsoup4` (PyPI) → `beautifulsoup4` (nixpkgs) ✓
182 - Package names with hyphens often work as-is
183 - If a package isn't found, suggest checking nixpkgs or using `buildPythonPackage`
184
1854. **Post-Creation Steps**: Always inform the user to:
186 - Files are automatically staged with `git add` if in a Git repo
187 - Run `nix flake check` to verify the flake configuration
188 - Run `nix flake update` to generate `flake.lock`
189 - Run `direnv allow` to activate direnv (or use `nix develop` manually)
190 - The `.envrc` and `.gitignore` updates are handled automatically
191
1925. **Git Integration**: Automatically stage files if in a git repo:
193 - `flake.nix`
194 - `.envrc`
195 - `.gitignore` (if modified/created)
196 - Remind user to commit and to add `flake.lock` after generation
197
1986. **Line Endings**: Always use Unix line endings (LF) for all generated files, especially `.envrc`. DOS line endings (CRLF) can cause issues with direnv and shell scripts on Unix systems.
199
200## Error Handling
201
202- If language detection finds no supported languages, create a minimal flake with empty packages list
203- If requirements.txt parsing fails, use `python3.withPackages` with an empty list of packages.
204- If user's system isn't `x86_64-linux`, ask which systems they need
205
206## Future Extensions
207
208The skill is designed to be easily extended with additional languages:
209- Rust: detect `Cargo.toml`, add `cargo`, `rustc`
210- Node.js: detect `package.json`, add `nodejs`, `nodePackages.npm`
211- Go: detect `go.mod`, add `go`
212- Java: detect `pom.xml` or `build.gradle`, add JDK
213
214To extend, add new detection criteria and package mappings following the existing pattern.