From 88ea196a9bdf52ba202006c5880afd96f0bdc72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Mon, 9 Mar 2026 16:32:45 +0300 Subject: [PATCH 01/21] modules.flake: reference `package` to be more extensible --- modules/flake/flint-git-hook.nix | 5 +++-- modules/flake/gitleaks-git-hook.nix | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/flake/flint-git-hook.nix b/modules/flake/flint-git-hook.nix index 643050d..cfca8b2 100644 --- a/modules/flake/flint-git-hook.nix +++ b/modules/flake/flint-git-hook.nix @@ -9,12 +9,13 @@ let ; in { - perSystem = { pkgs, ... }: { + perSystem = { config, pkgs, ... }: { pre-commit.settings.hooks = { flint = { name = "flint"; description = "Check flake dependencies"; - entry = "${getExe pkgs.notashelf.flint} --fail-if-multiple-versions"; + package = pkgs.notashelf.flint; + entry = "${getExe config.pre-commit.settings.hooks.flint.package} --fail-if-multiple-versions"; files = "^flake\.(nix|lock)$"; pass_filenames = false; }; diff --git a/modules/flake/gitleaks-git-hook.nix b/modules/flake/gitleaks-git-hook.nix index 7bb4dec..60d81ea 100644 --- a/modules/flake/gitleaks-git-hook.nix +++ b/modules/flake/gitleaks-git-hook.nix @@ -9,12 +9,13 @@ let ; in { - perSystem = { pkgs, ... }: { + perSystem = { config, pkgs, ... }: { pre-commit.settings.hooks = { gitleaks = { name = "gitleaks"; description = "Detect hardcoded secrets using Gitleaks"; - entry = "${getExe pkgs.gitleaks} git --pre-commit --redact --staged --verbose"; + package = pkgs.gitleaks; + entry = "${getExe config.pre-commit.settings.hooks.gitleaks.package} git --pre-commit --redact --staged --verbose"; pass_filenames = false; }; }; From 9a7019a92f5ff3aca225a129504d914948a895bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Mon, 9 Mar 2026 21:32:06 +0300 Subject: [PATCH 02/21] hm.zellij: make Claude a floating pane in code layout --- .zellij-layout.kdl | 2 +- users/ilkecan/utilities/zellij/layouts/code.nix | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.zellij-layout.kdl b/.zellij-layout.kdl index 039c412..8749ac1 100644 --- a/.zellij-layout.kdl +++ b/.zellij-layout.kdl @@ -31,7 +31,7 @@ layout { } } - tab focus=true name="Neovim" hide_floating_panes=true { + tab name="Neovim" focus=true hide_floating_panes=true { pane command="nvim" floating_panes { diff --git a/users/ilkecan/utilities/zellij/layouts/code.nix b/users/ilkecan/utilities/zellij/layouts/code.nix index a4edd63..189a031 100644 --- a/users/ilkecan/utilities/zellij/layouts/code.nix +++ b/users/ilkecan/utilities/zellij/layouts/code.nix @@ -8,9 +8,14 @@ layout._children = [ { tab = { - _props = { name = "Neovim"; focus = true; }; + _props = { name = "Neovim"; focus = true; hide_floating_panes = true; }; _children = [ { pane._props.command = "nvim"; } + { floating_panes.pane = { + _props = { command = "claude"; x = "10%"; y = "10%"; width = "80%"; height = "80%"; }; + args = [ "--ide" ]; + }; + } { pane = { _props = { size = 1; borderless = true; }; @@ -24,15 +29,7 @@ tab = { _props.name = "terminal"; _children = [ - { - pane = { - _props.split_direction = "vertical"; - _children = [ - { pane._props.command = config.home.defaultShell.meta.mainProgram; } - { pane._props = { command = "claude"; }; pane.start_suspended = true; } - ]; - }; - } + { pane._props.command = config.home.defaultShell.meta.mainProgram; } { pane = { _props = { size = 1; borderless = true; }; From 8cfe21d4bc91f78b67e1e4e22cb9e5fdfeeaa73c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Mon, 9 Mar 2026 22:39:14 +0300 Subject: [PATCH 03/21] hm.programs: configure `claude-code` --- users/ilkecan/default.nix | 2 +- .../dotfiles/.local/bin/starship-claude | 348 ++++++++++++++++++ users/ilkecan/llm.nix | 16 - users/ilkecan/llm/claude-code.nix | 21 ++ users/ilkecan/llm/default.nix | 9 + 5 files changed, 379 insertions(+), 17 deletions(-) create mode 100755 users/ilkecan/dotfiles/.local/bin/starship-claude delete mode 100644 users/ilkecan/llm.nix create mode 100644 users/ilkecan/llm/claude-code.nix create mode 100644 users/ilkecan/llm/default.nix diff --git a/users/ilkecan/default.nix b/users/ilkecan/default.nix index 9b348cc..4d69de2 100644 --- a/users/ilkecan/default.nix +++ b/users/ilkecan/default.nix @@ -21,7 +21,7 @@ in ./home-manager.nix ./input ./internet - ./llm.nix + ./llm ./multimedia ./networking ./nix diff --git a/users/ilkecan/dotfiles/.local/bin/starship-claude b/users/ilkecan/dotfiles/.local/bin/starship-claude new file mode 100755 index 0000000..7b16205 --- /dev/null +++ b/users/ilkecan/dotfiles/.local/bin/starship-claude @@ -0,0 +1,348 @@ +#!/usr/bin/env bash +# +# starship-claude - Use Starship for your Claude Code status line +# +# This script parses the claude code status line data to provide +# environment variables you can use in a standard Starship prompt. +# +# Formatted values (for display): +# - `CLAUDE_MODEL` - Short model name with icon (haiku/sonnet/opus) +# - `CLAUDE_MODEL_NERD` - Model with version (e.g., "󱚦 opus 4.5") +# - `CLAUDE_CONTEXT` - Context window usage percentage (left-padded, e.g., "15%") +# - `CLAUDE_COST` - Formatted session cost (e.g., "$0.71") +# - `CLAUDE_SUMMARY` - Session summary extracted from transcript +# - `CLAUDE_STAR` - Star character for prompt decoration +# +# Raw values (direct from JSON): +# - `CLAUDE_SESSION_ID` - Session UUID +# - `CLAUDE_TRANSCRIPT_PATH` - Path to session transcript JSONL +# - `CLAUDE_CWD` - Current working directory from session +# - `CLAUDE_WORKSPACE_CURRENT_DIR` - workspace.current_dir +# - `CLAUDE_WORKSPACE_PROJECT_DIR` - workspace.project_dir +# - `CLAUDE_VERSION` - Claude Code version +# - `CLAUDE_OUTPUT_STYLE` - Output style name +# - `CLAUDE_MODEL_ID` - Full model identifier (e.g., "claude-sonnet-4-5-20250929") +# - `CLAUDE_MODEL_DISPLAY_NAME` - Model display name (e.g., "Sonnet 4.5") +# - `CLAUDE_COST_RAW` - Raw cost in USD (number) +# - `CLAUDE_TOTAL_DURATION_MS` - Total session duration in ms +# - `CLAUDE_API_DURATION_MS` - Total API call duration in ms +# - `CLAUDE_LINES_ADDED` - Total lines added +# - `CLAUDE_LINES_REMOVED` - Total lines removed +# - `CLAUDE_TOTAL_INPUT_TOKENS` - Cumulative input tokens +# - `CLAUDE_TOTAL_OUTPUT_TOKENS` - Cumulative output tokens +# - `CLAUDE_CONTEXT_SIZE` - Context window size (e.g., 200000) +# - `CLAUDE_EXCEEDS_200K` - Whether session exceeds 200k tokens ("true"/"false") +# - `CLAUDE_INPUT_TOKENS` - Current usage input tokens +# - `CLAUDE_OUTPUT_TOKENS` - Current usage output tokens +# - `CLAUDE_CACHE_CREATION` - Cache creation input tokens +# - `CLAUDE_CACHE_READ` - Cache read input tokens +# +# Computed values: +# - `CLAUDE_CURRENT_TOKENS` - Sum of input + cache tokens (for context %) +# - `CLAUDE_PERCENT_RAW` - Raw percentage number (no padding) +# +# Also prints OSC 9;4 ConEmu terminal progress bar for context usage (optional) +# +# Repository: https://github.com/martinemde/starship-claude +# +# Usage: +# Add to ~/.claude/settings.json: +# { +# "statusLine": { +# "type": "command", +# "command": "~/.local/bin/starship-claude" +# } +# } +# +# Options can be added to the above command: +# --config PATH Use custom Starship config file location +# --path PATH Override the path context for starship prompt +# --no-progress Disable terminal context progress bar +# +# MIT License +# Copyright (c) 2026 Martin Emde +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +set -o errexit -o nounset -o pipefail + +# Configuration: context window progress thresholds +# I use Dex Horthy's dumb zone at 40% context usage +PROGRESS_COMPACT=80 # Percentage at which Claude Code compacts context +PROGRESS_YELLOW=40 # Warning threshold for progress bar +PROGRESS_RED=60 # Error threshold for progress bar + +# Configuration: model display names +# NerdFont icons used below which may not render (esp not on GitHub) +HAIKU=" haiku" +SONNET="󰚩 sonnet" +OPUS="󱚦 opus" + +# The star can help visually differentiate from other prompts. +# FYI: Official UI guidelines indicate #D97757 as Claude Orange +export CLAUDE_STAR="" + +# Parse command line options +show_progress=1 +starship_config="" +starship_path="" +while [ $# -gt 0 ]; do + case "$1" in + --no-progress) + show_progress=0 + shift + ;; + --config) + if [ $# -lt 2 ]; then + echo "Error: --config requires a path argument" >&2 + exit 1 + fi + starship_config="$2" + shift 2 + ;; + --path) + if [ $# -lt 2 ]; then + echo "Error: --path requires a path argument" >&2 + exit 1 + fi + starship_path="$2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done + +payload="$(cat || true)" + +if command -v jq >/dev/null 2>&1 && [ -n "$payload" ]; then + # + # Extract all values from JSON in a SINGLE jq call for performance + # Output format: newline-separated values in a known order + # + jq_output="$(printf '%s' "$payload" | jq -r ' + [ + # Raw values (indexes 0-17) + (.transcript_path // ""), # 0 + (.cwd // ""), # 1 + (.workspace.current_dir // ""), # 2 + (.workspace.project_dir // ""), # 3 + (.version // ""), # 4 + (.output_style.name // ""), # 5 + (.model.id // ""), # 6 + (.model.display_name // ""), # 7 + (.cost.total_cost_usd // ""), # 8 + (.cost.total_duration_ms // ""), # 9 + (.cost.total_api_duration_ms // ""), # 10 + (.cost.total_lines_added // ""), # 11 + (.cost.total_lines_removed // ""), # 12 + (.context_window.total_input_tokens // ""), # 13 + (.context_window.total_output_tokens // ""), # 14 + (if .exceeds_200k_tokens == null then "" else .exceeds_200k_tokens | tostring end), # 15 + (.session_id // ""), # 16 + (.context_window.context_window_size // ""), # 17 + # Current usage tokens (indexes 18-21) - empty if current_usage is null + (if .context_window.current_usage == null then "" else (.context_window.current_usage.input_tokens // 0) end), # 18 + (if .context_window.current_usage == null then "" else (.context_window.current_usage.output_tokens // 0) end), # 19 + (if .context_window.current_usage == null then "" else (.context_window.current_usage.cache_creation_input_tokens // 0) end), # 20 + (if .context_window.current_usage == null then "" else (.context_window.current_usage.cache_read_input_tokens // 0) end), # 21 + # Computed values (indexes 22-23) + (.model.display_name // .model.id // ""), # 22 - raw_model + (.workspace.current_dir // .workspace.project_dir // .cwd // "") # 23 - dir + ] | .[] + ')" + + # Parse jq output into an array (one element per line) + # Initialize with defaults to handle partial/failed jq output + values=("" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "") + + # Only parse if jq produced output + if [ -n "$jq_output" ]; then + if command -v mapfile >/dev/null 2>&1; then + mapfile -t values <<<"$jq_output" + else + # Fallback for shells without mapfile (zsh, older bash) + i=0 + while IFS= read -r line; do + values[i]="$line" + i=$((i + 1)) + done <<<"$jq_output" + fi + fi + + # Export raw values (use :- to handle missing array indices) + export CLAUDE_TRANSCRIPT_PATH="${values[0]:-}" + export CLAUDE_CWD="${values[1]:-}" + export CLAUDE_WORKSPACE_CURRENT_DIR="${values[2]:-}" + export CLAUDE_WORKSPACE_PROJECT_DIR="${values[3]:-}" + export CLAUDE_VERSION="${values[4]:-}" + export CLAUDE_OUTPUT_STYLE="${values[5]:-}" + export CLAUDE_MODEL_ID="${values[6]:-}" + export CLAUDE_MODEL_DISPLAY_NAME="${values[7]:-}" + export CLAUDE_COST_RAW="${values[8]:-}" + export CLAUDE_TOTAL_DURATION_MS="${values[9]:-}" + export CLAUDE_API_DURATION_MS="${values[10]:-}" + export CLAUDE_LINES_ADDED="${values[11]:-}" + export CLAUDE_LINES_REMOVED="${values[12]:-}" + export CLAUDE_TOTAL_INPUT_TOKENS="${values[13]:-}" + export CLAUDE_TOTAL_OUTPUT_TOKENS="${values[14]:-}" + export CLAUDE_EXCEEDS_200K="${values[15]:-}" + export CLAUDE_SESSION_ID="${values[16]:-}" + export CLAUDE_CONTEXT_SIZE="${values[17]:-}" + export CLAUDE_INPUT_TOKENS="${values[18]:-}" + export CLAUDE_OUTPUT_TOKENS="${values[19]:-}" + export CLAUDE_CACHE_CREATION="${values[20]:-}" + export CLAUDE_CACHE_READ="${values[21]:-}" + + raw_model="${values[22]:-}" + dir="${values[23]:-}" + + # cd into workspace dir + if [ -n "$dir" ] && [ -d "$dir" ]; then + cd "$dir" + fi + + # + # Short model name: haiku / sonnet / opus (pure bash, no external commands) + # + if [ -n "$raw_model" ]; then + # Lowercase using bash parameter expansion (bash 4+) or tr fallback + if [[ "${BASH_VERSINFO[0]:-0}" -ge 4 ]]; then + lower_model="${raw_model,,}" + else + lower_model="$(printf '%s' "$raw_model" | tr '[:upper:]' '[:lower:]')" + fi + + case "$lower_model" in + *haiku*) short_model="$HAIKU" ;; + *sonnet*) short_model="$SONNET" ;; + *opus*) short_model="$OPUS" ;; + *) short_model="$raw_model" ;; + esac + + export CLAUDE_MODEL="$short_model" + export CLAUDE_MODEL_NERD="$short_model" + + # Extract version number using bash regex (no sed/grep) + if [[ "$raw_model" =~ ([0-9]+)\.([0-9]+) ]]; then + export CLAUDE_MODEL_NAME="$short_model ${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" + else + export CLAUDE_MODEL_NAME="$short_model" + fi + fi + + # + # Cost: format as $X.XX (only if we have a value) + # + raw_cost="${values[8]:-}" + if [ -n "$raw_cost" ]; then + export CLAUDE_COST="$(printf '$%.2f' "$raw_cost")" + fi + + # + # Session summary from transcript JSONL file + # + export CLAUDE_SUMMARY="" + transcript_path="${values[0]:-}" + if [ -n "$transcript_path" ] && [ -f "$transcript_path" ]; then + summary="$(jq -rs '[.[] | select(.type == "summary")] | last | .summary // empty' "$transcript_path")" + if [ -n "$summary" ]; then + # Sanitize: replace newlines with spaces, collapse whitespace, trim + summary="${summary//$'\n'/ }" # newlines to spaces + summary="${summary// / }" # collapse double spaces (basic) + summary="${summary# }" # trim leading + summary="${summary% }" # trim trailing + export CLAUDE_SUMMARY="$summary" + fi + fi + + # + # Context window usage percentage + # + context_size="${values[17]:-}" + input_tokens="${values[18]:-}" + cache_creation="${values[20]:-}" + cache_read="${values[21]:-}" + + if [ -n "$context_size" ] && [ "$context_size" != "null" ] && [ -n "$input_tokens" ]; then + # Use 0 defaults for arithmetic when values exist but individual fields might be missing + current_tokens=$((${input_tokens:-0} + ${cache_creation:-0} + ${cache_read:-0})) + export CLAUDE_CURRENT_TOKENS="$current_tokens" + + if [ "$current_tokens" -gt 0 ]; then + percent_used=$((current_tokens * 100 / context_size)) + export CLAUDE_PERCENT_RAW="$percent_used" + export CLAUDE_CONTEXT="$(printf '%3s' "${percent_used}%")" + else + export CLAUDE_CONTEXT=" %" + fi + else + export CLAUDE_CONTEXT=" %" + fi +fi + +# Allow overriding starship command for testing +# Set STARSHIP_CMD to use a custom command (e.g., 'env' for testing) +starship_cmd="${STARSHIP_CMD:-starship}" + +# Determine Starship config path +# Priority: --config flag > default location +if [ -z "$starship_config" ]; then + starship_config="$HOME/.claude/starship.toml" +fi + +# Build starship prompt arguments +starship_args="prompt" +if [ -n "$starship_path" ]; then + starship_args="$starship_args --path $starship_path" +fi + +# Force non-zsh-style output so we don't get %{%} markers +STARSHIP_CONFIG="$starship_config" \ + STARSHIP_SHELL=sh \ + $starship_cmd $starship_args + +# Terminal progress bar (OSC 9;4) - sent AFTER starship to avoid render conflicts +# Can be disabled via --no-progress flag +if [ "$show_progress" = "1" ]; then + if [ -n "${percent_used:-}" ]; then + # Scale progress bar: 0-PROGRESS_COMPACT% context maps to 0-100% progress + # Claude compacts at PROGRESS_COMPACT%, so treat that as "full" + if [ "$percent_used" -ge "$PROGRESS_COMPACT" ]; then + progress_percent=100 + else + progress_percent=$((percent_used * 100 / PROGRESS_COMPACT)) + fi + + # OSC 9;4 progress bar: ESC ] 9 ; 4 ; ; BEL + # State based on actual context usage: + # 0-PROGRESS_YELLOW%: normal (state 1), PROGRESS_YELLOW-PROGRESS_RED%: warning (state 4), PROGRESS_RED%+: error (state 2) + if [ "$percent_used" -ge "$PROGRESS_RED" ]; then + progress_state=2 # Error + elif [ "$percent_used" -ge "$PROGRESS_YELLOW" ]; then + progress_state=4 # Warning + else + progress_state=1 # Normal + fi + printf '\033]9;4;%d;%d\a' "$progress_state" "$progress_percent" >/dev/tty 2>/dev/null || true + fi + # Don't clear progress bar when data is missing - just leave it alone +fi diff --git a/users/ilkecan/llm.nix b/users/ilkecan/llm.nix deleted file mode 100644 index 9c96e9f..0000000 --- a/users/ilkecan/llm.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - pkgs, - ... -}: - -{ - home = { - sessionVariables = { - CLAUDE_CODE_DISABLE_AUTO_MEMORY = 0; - }; - - packages = with pkgs.llm-agents; [ - claude-code - ]; - }; -} diff --git a/users/ilkecan/llm/claude-code.nix b/users/ilkecan/llm/claude-code.nix new file mode 100644 index 0000000..e796e1e --- /dev/null +++ b/users/ilkecan/llm/claude-code.nix @@ -0,0 +1,21 @@ +{ + pkgs, + ... +}: + +{ + home = { + sessionVariables = { + CLAUDE_CODE_DISABLE_AUTO_MEMORY = 0; + }; + + packages = with pkgs; [ starship ]; + }; + + programs = { + claude-code = { + enable = true; + package = pkgs.llm-agents.claude-code; + }; + }; +} diff --git a/users/ilkecan/llm/default.nix b/users/ilkecan/llm/default.nix new file mode 100644 index 0000000..df008e2 --- /dev/null +++ b/users/ilkecan/llm/default.nix @@ -0,0 +1,9 @@ +{ + ... +}: + +{ + imports = [ + ./claude-code.nix + ]; +} From 323fd5fd7e2cb6de38deca3b645b14159b42f826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Mon, 9 Mar 2026 23:53:58 +0300 Subject: [PATCH 04/21] hm: configure `mcp-servers` --- flake.lock | 21 +++++++++++++++++++++ flake.nix | 4 ++++ flake/home-configurations.nix | 1 + inputs/home-manager.nix | 6 ++++++ users/ilkecan/llm/claude-code.nix | 1 + users/ilkecan/llm/mcp.nix | 23 +++++++++++++++++++++++ 6 files changed, 56 insertions(+) create mode 100644 users/ilkecan/llm/mcp.nix diff --git a/flake.lock b/flake.lock index 2d0f92c..ebdb7bc 100644 --- a/flake.lock +++ b/flake.lock @@ -461,6 +461,26 @@ "type": "github" } }, + "mcp-servers-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1773082783, + "narHash": "sha256-210SLx2URE5aIfjVY6R/0KMj1OFe80G0kKk1LTrLmfY=", + "owner": "natsukium", + "repo": "mcp-servers-nix", + "rev": "8c6b332a6a09d364eb4817f1ccf6a37bcc737556", + "type": "github" + }, + "original": { + "owner": "natsukium", + "repo": "mcp-servers-nix", + "type": "github" + } + }, "mnw": { "locked": { "lastModified": 1758834834, @@ -866,6 +886,7 @@ "impermanence": "impermanence", "import-tree": "import-tree", "llm-agents": "llm-agents", + "mcp-servers-nix": "mcp-servers-nix", "niri-flake": "niri-flake", "nix-alien": "nix-alien", "nix-ast-lint": "nix-ast-lint", diff --git a/flake.nix b/flake.nix index 006a52a..392d462 100644 --- a/flake.nix +++ b/flake.nix @@ -83,6 +83,10 @@ treefmt-nix.follows = "treefmt-nix"; }; }; + mcp-servers-nix = { + url = "github:natsukium/mcp-servers-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; niri-flake = { url = "github:sodiboo/niri-flake"; inputs = { diff --git a/flake/home-configurations.nix b/flake/home-configurations.nix index 59bc3f8..1323d0c 100644 --- a/flake/home-configurations.nix +++ b/flake/home-configurations.nix @@ -24,6 +24,7 @@ let inputs.dms-plugin-registry.homeModules.default inputs.dms.homeModules.dank-material-shell inputs.dms.homeModules.niri + inputs.mcp-servers-nix.homeManagerModules.default inputs.niri-flake.homeModules.niri inputs.niri-flake.homeModules.stylix inputs.nix-flatpak.homeManagerModules.nix-flatpak diff --git a/inputs/home-manager.nix b/inputs/home-manager.nix index 3a66cd9..bd8d3b0 100644 --- a/inputs/home-manager.nix +++ b/inputs/home-manager.nix @@ -8,5 +8,11 @@ src = inputs.home-manager; name = "home-manager"; pulls = { + "8290" = "sha256-hSnOwFX04GQcOwlxPsDJxVV8b6FIFvuckCAm0fjfLvI="; + "8305" = "sha256-osWWAfqhc9X8QlGjSe4cnffj/ljB+KQGfSLT3o4Dd60="; + "8365" = "sha256-AKXVJmltOEiYu71gTb5yhlKTP21Ce0vuEogstWOAUa8="; + "8770" = "sha256-1GctHo6/qowbuguH335KDtn3nAgwn6+cGlebfuE2QiY="; + "8543" = "sha256-Swwm+ejwIKVI4tQy7ilPNwMoUlBejPm2NfMDrY+dJz0="; + "8783" = "sha256-W8Ufvufloq3gNT2zxegKQUHmi3KZMlcQCp9gEi0ZHuE="; }; } diff --git a/users/ilkecan/llm/claude-code.nix b/users/ilkecan/llm/claude-code.nix index e796e1e..d8a5c7a 100644 --- a/users/ilkecan/llm/claude-code.nix +++ b/users/ilkecan/llm/claude-code.nix @@ -16,6 +16,7 @@ claude-code = { enable = true; package = pkgs.llm-agents.claude-code; + enableMcpIntegration = true; }; }; } diff --git a/users/ilkecan/llm/mcp.nix b/users/ilkecan/llm/mcp.nix new file mode 100644 index 0000000..60f4961 --- /dev/null +++ b/users/ilkecan/llm/mcp.nix @@ -0,0 +1,23 @@ +{ + ... +}: + +{ + # https://github.com/natsukium/mcp-servers-nix + mcp-servers.programs = { + fetch.enable = true; + git.enable = true; + github.enable = true; + memory.enable = true; + nixos.enable = true; + sequential-thinking.enable = true; + serena = { enable = true; context = "claude-code"; enableWebDashboard = true; }; + terraform.enable = true; + }; + + programs.mcp = { + enable = true; + servers = { + }; + }; +} From 85a23fc01fcc801f66bbd4e6ef77e46d27d739bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Mon, 9 Mar 2026 23:57:05 +0300 Subject: [PATCH 05/21] git-hooks: enable `ripsecrets` --- flake/per-system/pre-commit.nix | 1 + users/ilkecan/security/default.nix | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/flake/per-system/pre-commit.nix b/flake/per-system/pre-commit.nix index 0ca055c..699e913 100644 --- a/flake/per-system/pre-commit.nix +++ b/flake/per-system/pre-commit.nix @@ -13,6 +13,7 @@ gitleaks.enable = true; nil.enable = true; nixf-diagnose.enable = true; + ripsecrets.enable = true; }; }; }; diff --git a/users/ilkecan/security/default.nix b/users/ilkecan/security/default.nix index 2a7ad04..9eb8b52 100644 --- a/users/ilkecan/security/default.nix +++ b/users/ilkecan/security/default.nix @@ -12,7 +12,8 @@ home.packages = with pkgs; [ age bubblewrap # https://github.com/containers/bubblewrap - gitleaks # https://github.com/gitleaks/gitleaks + gitleaks # https://github.com/gitleaks/gitleaks + ripsecrets # https://github.com/sirwart/ripsecrets sops ssh-to-age trufflehog # https://github.com/trufflesecurity/trufflehog From f799533791b254714d8ca4e81749d746b2cbabcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 00:53:02 +0300 Subject: [PATCH 06/21] nixos.nix: enable `impure-derivations` --- hosts/mephistopheles/nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts/mephistopheles/nix/default.nix b/hosts/mephistopheles/nix/default.nix index 6f262da..c636e19 100644 --- a/hosts/mephistopheles/nix/default.nix +++ b/hosts/mephistopheles/nix/default.nix @@ -33,6 +33,7 @@ in settings = { experimental-features = [ "flakes" + "impure-derivations" "nix-command" "no-url-literals" ]; From 68eb4caab360929abe55d9254dd951fbb567ae7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 00:53:37 +0300 Subject: [PATCH 07/21] .gitignore: add `/result*` --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 644b766..25e9f70 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.direnv/ /.pre-commit-config.yaml +/result* From 98a6e8e1ebaf180496f20b40dc72e670ad86f6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 14:26:47 +0300 Subject: [PATCH 08/21] nixos.nix: enable `ca-derivations` --- hosts/mephistopheles/nix/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts/mephistopheles/nix/default.nix b/hosts/mephistopheles/nix/default.nix index c636e19..6118fda 100644 --- a/hosts/mephistopheles/nix/default.nix +++ b/hosts/mephistopheles/nix/default.nix @@ -32,6 +32,7 @@ in settings = { experimental-features = [ + "ca-derivations" "flakes" "impure-derivations" "nix-command" From 7bef82107498470889b9236e15f6d12451a6e4ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 14:40:41 +0300 Subject: [PATCH 09/21] packages.nix-fast-build: build from last commit ... and apply patch to support `impure-derivations`. --- inputs/default.nix | 4 ++-- packages/default.nix | 10 ++++++++-- packages/nix-fast-build.nix | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 packages/nix-fast-build.nix diff --git a/inputs/default.nix b/inputs/default.nix index 2fddcf7..74dad60 100644 --- a/inputs/default.nix +++ b/inputs/default.nix @@ -17,9 +17,9 @@ let patchInput = { owner, repo, src, name, pulls, patches ? [ ] }: let - mkPatch = number: sha256: + mkPatch = number: hash: { - inherit sha256; + inherit hash; name = "${owner}-${repo}-${number}.patch"; url = "https://github.com/${owner}/${repo}/pull/${number}.patch?full_index=1"; }; diff --git a/packages/default.nix b/packages/default.nix index c457ca4..37c34b9 100644 --- a/packages/default.nix +++ b/packages/default.nix @@ -40,6 +40,9 @@ import inputs.nixpkgs { nur = (inputs.nur.overlays.default final.unstable final.unstable).nur; }) + inputs.llm-agents.overlays.default + inputs.nix-alien.overlays.default + (final: _prev: { notashelf = { inherit (inputs.flint.packages.${final.stdenv.hostPlatform.system}) flint; @@ -48,7 +51,10 @@ import inputs.nixpkgs { inherit (inputs.nix-ast-lint.packages.${final.stdenv.hostPlatform.system}) nix-ast-lint; }) - inputs.llm-agents.overlays.default - inputs.nix-alien.overlays.default + (_final: prev: { + unstable = prev.unstable // { + nix-fast-build = prev.unstable.callPackage ./nix-fast-build.nix { }; + }; + }) ]; } diff --git a/packages/nix-fast-build.nix b/packages/nix-fast-build.nix new file mode 100644 index 0000000..968803f --- /dev/null +++ b/packages/nix-fast-build.nix @@ -0,0 +1,20 @@ +{ + fetchpatch2, + nix-fast-build, +}: + +nix-fast-build.overrideAttrs (prev: { + version = "${prev.version}-unstable-2026-03-08"; + src = prev.src.override { + tag = null; + rev = "dde85ca993e9709dce1932c679baa2436cd00127"; + hash = "sha256-ZPlRNdkgKBeo6J0S51JZRFBGq/tFfd7oVqAz2a9ytuM="; + }; + patches = (prev.patches or []) ++ [ + (fetchpatch2 { + name = "use-nix-build-subcommand.patch"; + url = "https://patch-diff.githubusercontent.com/raw/Mic92/nix-fast-build/pull/301.patch"; + hash = "sha256-a6c0rq45Brr4JBe2ncqUQmJx3tmr6iqaMT3IwSOzleg="; + }) + ]; +}) From 6ca7a17ae1a29d48186a01148211218ec497c362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 14:54:20 +0300 Subject: [PATCH 10/21] flake.checks: add `trufflehog` --- flake/per-system/checks/default.nix | 18 ++++++++++++++++++ flake/per-system/checks/trufflehog.nix | 12 ++++++++++++ flake/per-system/default.nix | 1 + 3 files changed, 31 insertions(+) create mode 100644 flake/per-system/checks/default.nix create mode 100644 flake/per-system/checks/trufflehog.nix diff --git a/flake/per-system/checks/default.nix b/flake/per-system/checks/default.nix new file mode 100644 index 0000000..8d248f0 --- /dev/null +++ b/flake/per-system/checks/default.nix @@ -0,0 +1,18 @@ +{ + self, + ... +}: + +{ + perSystem = { pkgs, ... }: + let + args = { inherit pkgs self; }; + mkCheck = file: + import file args; + in + { + checks = { + trufflehog = mkCheck ./trufflehog.nix; + }; + }; +} diff --git a/flake/per-system/checks/trufflehog.nix b/flake/per-system/checks/trufflehog.nix new file mode 100644 index 0000000..7174a5f --- /dev/null +++ b/flake/per-system/checks/trufflehog.nix @@ -0,0 +1,12 @@ +{ + pkgs, + self, +}: + +pkgs.runCommand "trufflehog-check" { + nativeBuildInputs = with pkgs; [ trufflehog ]; + __impure = true; +} '' + trufflehog filesystem ${self} --github-actions --fail --results=verified + touch $out +'' diff --git a/flake/per-system/default.nix b/flake/per-system/default.nix index 51a00aa..c0dbdbf 100644 --- a/flake/per-system/default.nix +++ b/flake/per-system/default.nix @@ -6,6 +6,7 @@ imports = [ ./apps ./args + ./checks ./dev-shells.nix ./pre-commit.nix ]; From c2a93c4ebf3a88219ef572ee9ae73784133e7da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 15:05:54 +0300 Subject: [PATCH 11/21] gh.workflows.ci: explicitly set `experimental-features` --- .github/workflows/ci.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f24a368..0b5aa54 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -9,7 +9,7 @@ jobs: check: runs-on: ubuntu-latest permissions: - contents: read # required for `actions/checkout` + contents: read # required for `actions/checkout` steps: - uses: actions/checkout@v6 @@ -18,6 +18,9 @@ jobs: nix-permission-edict: true - uses: nixbuild/nix-quick-install-action@v34 + with: + nix_conf: | + experimental-features = ca-derivations flakes impure-derivations nix-command no-url-literals - run: nix run env: From 1f4faa351514fbb60d13149869c508167e2e3b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 15:37:20 +0300 Subject: [PATCH 12/21] flake: update inputs --- flake.lock | 74 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/flake.lock b/flake.lock index ebdb7bc..86ee2da 100644 --- a/flake.lock +++ b/flake.lock @@ -202,11 +202,11 @@ ] }, "locked": { - "lastModified": 1772913452, - "narHash": "sha256-ViJzEi2rv0OPqKMWxxu1dR73EjuRoci1jxtp6O1PR+0=", + "lastModified": 1773142806, + "narHash": "sha256-LCucRiPA3m6i7OM0rB+iT2oeFzIa008xxa4xkBkD/aU=", "owner": "AvengeMedia", "repo": "dms-plugin-registry", - "rev": "547f10eae04b3cb3dbb16029d3ac38c45174f9e0", + "rev": "08e551b79aef5bd534b3e97b032bd3b282d7c99c", "type": "github" }, "original": { @@ -374,11 +374,11 @@ ] }, "locked": { - "lastModified": 1772633058, - "narHash": "sha256-SO7JapRy2HPhgmqiLbfnW1kMx5rakPMKZ9z3wtRLQjI=", + "lastModified": 1772985280, + "narHash": "sha256-FdrNykOoY9VStevU4zjSUdvsL9SzJTcXt4omdEDZDLk=", "owner": "nix-community", "repo": "home-manager", - "rev": "080657a04188aca25f8a6c70a0fb2ea7e37f1865", + "rev": "8f736f007139d7f70752657dff6a401a585d6cbc", "type": "github" }, "original": { @@ -413,11 +413,11 @@ }, "import-tree": { "locked": { - "lastModified": 1772344373, - "narHash": "sha256-OQQ1MhB9t1J71b2wxRRTdH/Qd8UGG0p+dGspfCf5U1c=", + "lastModified": 1772999353, + "narHash": "sha256-dPb0WxUhFaz6wuR3B6ysqFJpsu8txKDPZvS47AT2XLI=", "owner": "vic", "repo": "import-tree", - "rev": "10fda59eee7d7970ec443b925f32a1bc7526648c", + "rev": "545a4df146fce44d155573e47f5a777985acf912", "type": "github" }, "original": { @@ -448,11 +448,11 @@ ] }, "locked": { - "lastModified": 1772894523, - "narHash": "sha256-GDjaSrB39dibyzaZHfxtOJBE4M0K9ws/DcJ8cLZmEjY=", + "lastModified": 1773133636, + "narHash": "sha256-4Wjgp7vc3tq7erE/JRI3XXtLj9eM6s1lVK9GMkILy7k=", "owner": "numtide", "repo": "llm-agents.nix", - "rev": "6de17762e82217f80633609f8fa8d8031a80d82f", + "rev": "126d61f41fb20ff99025bf7de481a211593ec7c7", "type": "github" }, "original": { @@ -468,11 +468,11 @@ ] }, "locked": { - "lastModified": 1773082783, - "narHash": "sha256-210SLx2URE5aIfjVY6R/0KMj1OFe80G0kKk1LTrLmfY=", + "lastModified": 1773105430, + "narHash": "sha256-r+JWt5SyeCafJiEaEjB9pmcldeG0Uc+er/8dWFS+Rjs=", "owner": "natsukium", "repo": "mcp-servers-nix", - "rev": "8c6b332a6a09d364eb4817f1ccf6a37bcc737556", + "rev": "39444c3e94a1bb740a797decb97beef0a6abc384", "type": "github" }, "original": { @@ -537,11 +537,11 @@ ] }, "locked": { - "lastModified": 1772884214, - "narHash": "sha256-nl1U1E9Kk9ZmxWdqcwBuFaljxknbrwq8/bY+utQSajk=", + "lastModified": 1773132826, + "narHash": "sha256-rp7A5sq1TlFOku9Hl71g3jXEv6MBV8WmwkuAYpbzps0=", "owner": "sodiboo", "repo": "niri-flake", - "rev": "3fc5b3670ef77356173ca5f1fa5015e01204bc33", + "rev": "68e2bf48958f2d3553c2efdd518cab55a9236393", "type": "github" }, "original": { @@ -640,11 +640,11 @@ ] }, "locked": { - "lastModified": 1772906589, - "narHash": "sha256-RF6tdst0P1es2yY0w1BjptAzBPYNVUIRbjJ6cKOvefI=", + "lastModified": 1773109921, + "narHash": "sha256-R3xsyVFVmyzQH4k0wm06TffrvDlZVKzoRGJk9i4h20Q=", "owner": "fufexan", "repo": "nix-gaming", - "rev": "a2456108efbdb96c0a5c2d5f733bdf8704da8254", + "rev": "7bf06657436a10124b3d02de120300b4bbbfe46d", "type": "github" }, "original": { @@ -660,11 +660,11 @@ ] }, "locked": { - "lastModified": 1772341813, - "narHash": "sha256-/PQ0ubBCMj/MVCWEI/XMStn55a8dIKsvztj4ZVLvUrQ=", + "lastModified": 1772945408, + "narHash": "sha256-PMt48sEQ8cgCeljQ9I/32uoBq/8t8y+7W/nAZhf72TQ=", "owner": "nix-community", "repo": "nix-index-database", - "rev": "a2051ff239ce2e8a0148fa7a152903d9a78e854f", + "rev": "1c1d8ea87b047788fd7567adf531418c5da321ec", "type": "github" }, "original": { @@ -686,11 +686,11 @@ ] }, "locked": { - "lastModified": 1772891434, - "narHash": "sha256-+MUN+5lOvWS6T4pvIZBGL4AKJkflLXGgVRYTlNeZEiE=", + "lastModified": 1773103371, + "narHash": "sha256-qXKxc4qzqUaFL9WTS9+nNk/81ga8MpoeiH30GnKxabU=", "owner": "kaylorben", "repo": "nixcord", - "rev": "fc63af2dbc92cdcfeb6c650d986280057b0f135c", + "rev": "d74f4615030b24db7857b49ff68a02f579b34c1b", "type": "github" }, "original": { @@ -759,11 +759,11 @@ }, "nixpkgs-unstable": { "locked": { - "lastModified": 1772773019, - "narHash": "sha256-nbKkTH2oRlWaAjeDh/QMraqjfj/C2xJFa53twFzRd8o=", - "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", + "lastModified": 1772963539, + "narHash": "sha256-G4+9cEu8XSqEWYUB6iRgDfrg53av6yyRwAKhSeKbUVw=", + "rev": "9dcb002ca1690658be4a04645215baea8b95f31d", "type": "tarball", - "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre958961.aca4d95fce49/nixexprs.tar.xz" + "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre960399.9dcb002ca169/nixexprs.tar.xz" }, "original": { "type": "tarball", @@ -780,11 +780,11 @@ ] }, "locked": { - "lastModified": 1772917034, - "narHash": "sha256-bf8GOnmGrrXd3NpCa+zuY6ets3QGBnbnIhBaMsVteIg=", + "lastModified": 1773143870, + "narHash": "sha256-B4UpQWRLwmXsdG8gg1d0NJnuJ3UK6G+XQysZ0y3TSPg=", "owner": "nix-community", "repo": "NUR", - "rev": "9f4b9e8a48b7f7f14b26796bac9a982a40386ce7", + "rev": "d2268b695ea2d53b9975c7c7584b3acb057eb11b", "type": "github" }, "original": { @@ -914,11 +914,11 @@ ] }, "locked": { - "lastModified": 1772495394, - "narHash": "sha256-hmIvE/slLKEFKNEJz27IZ8BKlAaZDcjIHmkZ7GCEjfw=", + "lastModified": 1773096132, + "narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=", "owner": "Mic92", "repo": "sops-nix", - "rev": "1d9b98a29a45abe9c4d3174bd36de9f28755e3ff", + "rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784", "type": "github" }, "original": { From 4027e036c441904c876931c38615a5d8483dcb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 16:30:31 +0300 Subject: [PATCH 13/21] hm.mcp: actually enable `mcp-servers` --- users/ilkecan/llm/claude-code.nix | 7 ++++++- users/ilkecan/llm/default.nix | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/users/ilkecan/llm/claude-code.nix b/users/ilkecan/llm/claude-code.nix index d8a5c7a..f925247 100644 --- a/users/ilkecan/llm/claude-code.nix +++ b/users/ilkecan/llm/claude-code.nix @@ -15,7 +15,12 @@ programs = { claude-code = { enable = true; - package = pkgs.llm-agents.claude-code; + package = (pkgs.llm-agents.claude-code.override { + disableTelemetry = true; + }).overrideAttrs (prev: { + # TODO: remove this after 26.05 + meta = prev.meta // { maintainers = [ ]; }; # to fix `attribute 'ryoppippi' missing` + }); enableMcpIntegration = true; }; }; diff --git a/users/ilkecan/llm/default.nix b/users/ilkecan/llm/default.nix index df008e2..a862462 100644 --- a/users/ilkecan/llm/default.nix +++ b/users/ilkecan/llm/default.nix @@ -5,5 +5,6 @@ { imports = [ ./claude-code.nix + ./mcp.nix ]; } From c54e0b26bc8474f6dc8e9beb5bb24bf36c324f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 16:47:42 +0300 Subject: [PATCH 14/21] hm.packages: add `sandbox-runtime` --- users/ilkecan/llm/claude-code.nix | 4 +++- users/ilkecan/security/default.nix | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/users/ilkecan/llm/claude-code.nix b/users/ilkecan/llm/claude-code.nix index f925247..287eaa5 100644 --- a/users/ilkecan/llm/claude-code.nix +++ b/users/ilkecan/llm/claude-code.nix @@ -9,7 +9,9 @@ CLAUDE_CODE_DISABLE_AUTO_MEMORY = 0; }; - packages = with pkgs; [ starship ]; + packages = with pkgs; [ + starship # https://github.com/starship/starship - https://github.com/martinemde/starship-claude + ]; }; programs = { diff --git a/users/ilkecan/security/default.nix b/users/ilkecan/security/default.nix index 9eb8b52..2101d31 100644 --- a/users/ilkecan/security/default.nix +++ b/users/ilkecan/security/default.nix @@ -13,6 +13,7 @@ age bubblewrap # https://github.com/containers/bubblewrap gitleaks # https://github.com/gitleaks/gitleaks + llm-agents.sandbox-runtime # https://github.com/anthropic-experimental/sandbox-runtime ripsecrets # https://github.com/sirwart/ripsecrets sops ssh-to-age From bebf4d1b64fd23fe097ca7cc681ca3771f598ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 17:02:29 +0300 Subject: [PATCH 15/21] hm.packages: add lsp servers for `claude` - clangd - lua-language-server - pyright - rust-analyzer - typescript-language-server --- users/ilkecan/development/default.nix | 1 + users/ilkecan/development/lsp.nix | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 users/ilkecan/development/lsp.nix diff --git a/users/ilkecan/development/default.nix b/users/ilkecan/development/default.nix index 7bf3039..00f565a 100644 --- a/users/ilkecan/development/default.nix +++ b/users/ilkecan/development/default.nix @@ -6,6 +6,7 @@ { imports = [ ./debugging.nix + ./lsp.nix ./static-program-analysis ./version-control ]; diff --git a/users/ilkecan/development/lsp.nix b/users/ilkecan/development/lsp.nix new file mode 100644 index 0000000..143b9a3 --- /dev/null +++ b/users/ilkecan/development/lsp.nix @@ -0,0 +1,14 @@ +{ + pkgs, + ... +}: + +{ + home.packages = with pkgs; [ + clang-tools # https://github.com/llvm/llvm-project/tree/main/clang-tools-extra/clangd + lua-language-server # https://github.com/luals/lua-language-server + pyright # https://github.com/Microsoft/pyright + rust-analyzer # https://github.com/rust-lang/rust-analyzer + typescript-language-server # https://github.com/typescript-language-server/typescript-language-server + ]; +} From 0833d01b05de791aa2dc4df859b8d540c4bea4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Tue, 10 Mar 2026 23:51:47 +0300 Subject: [PATCH 16/21] CLAUDE.md: symlink to AGENTS.md & update --- AGENTS.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 97 +------------------------------------------ 2 files changed, 122 insertions(+), 96 deletions(-) create mode 100644 AGENTS.md mode change 100644 => 120000 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e2cdd67 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,121 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What This Is + +A NixOS + Home Manager configuration flake for one host (`mephistopheles`, a Lenovo ThinkPad E14 Gen7 Intel) and one user (`ilkecan`). Built with `flake-parts`. + +## Common Commands + +`nh` is configured with the flake path and used for all build/switch operations. The zellij layout (`.zellij-layout.kdl`) has dedicated panes for these: + +```bash +nh os switch # Rebuild and activate NixOS configuration +nh os repl # NixOS config REPL +nh home switch # Rebuild and activate Home Manager configuration +nh home repl # Home Manager config REPL +``` + +The raw `nix` CLI is used for flake-level operations: + +```bash +nix flake update [input] # Update flake inputs +nix flake metadata # Show input metadata +nix flake check # Check for evaluation errors +``` + +## Repository Structure + +``` +flake.nix # Entry point: delegates to flake-parts via ./flake +flake/ # Flake-parts modules defining all outputs + nixos-configurations.nix + home-configurations.nix + modules.nix # Exposes modules/ tree as flake.modules + flake-modules.nix # flake.flakeModules = modules.flake + home-modules.nix # flake.homeModules = modules.homeManager + nixos-modules.nix # flake.nixosModules = modules.nixos + per-system/ # All perSystem outputs + args/ # Injects custom perSystem args (lib, pkgs) + apps/ # Flake apps (ci via nix-fast-build) + checks/ # Flake checks (trufflehog) + dev-shells.nix # devShells (pre-commit shell) + pre-commit.nix # git-hooks-nix pre-commit config +inputs/ # Applies patches to flake inputs + default.nix # Merges patched inputs over raw inputs + nixpkgs.nix # nixpkgs patches (module-level changes) + nixpkgs-patched.nix # nixpkgs-unstable patches (package-level changes) + home-manager.nix # home-manager patches + dms.nix # dms patches +lib/ # Custom lib extensions (lib.my.*) + my.nix # lib.my.importTree, lib.my.mkAbsolute + my-pkgs.nix # lib.my-pkgs.callExpression +hosts/mephistopheles/ # NixOS host configuration +users/ilkecan/ # Home Manager user configuration +modules/ # Reusable modules, exposed as flake outputs + flake/ # Flake-parts modules (flakeModules) + home-manager/ # Home Manager modules (homeModules) + nixos/ # NixOS modules (nixosModules) +packages/ # Custom pkgs instantiation (overlays applied here) +secrets/ # sops-nix encrypted secrets +``` + +## Key Architectural Patterns + +### Three nixpkgs Inputs + +There are three nixpkgs inputs with distinct purposes: + +- **`nixpkgs`** (stable, `nixos-25.11`) — base system. Patched in-place (overwrites itself in `inputs`) with **module-level** changes only (no package rebuilds). +- **`nixpkgs-unstable`** — always the original unpatched unstable channel. Exposed as `pkgs.unstable` overlay for select tools that need newer versions. +- **`nixpkgs-patched`** — patched version of `nixpkgs-unstable`, stored as a separate input. Used for **package-level** changes to contain cascade rebuilds: patching a package in `nixpkgs-unstable` directly could trigger rebuilds for all dependents; isolating it in a named input limits the blast radius to what explicitly uses `pkgs.patched`. + +### Input Patching +`inputs/default.nix` applies upstream PRs to inputs and makes patched versions transparent by overwriting the originals under `inputs.*` (except `nixpkgs-patched`, which is always a separate input). Modules consume patched inputs the same way as stock ones. + +### Custom pkgs Overlays +`packages/default.nix` instantiates nixpkgs with several overlays, making these package sets available everywhere: +- `pkgs.unstable` — nixos-unstable packages +- `pkgs.patched` — nixpkgs-unstable with package-level patches applied +- `pkgs.nur` — NUR packages +- `pkgs.notashelf` — packages from the flint flake +- `pkgs.llm-agents.*` — LLM agent tools + +### lib.my.importTree +Used extensively to auto-import directories. All `.nix` files and subdirectories are imported recursively, controlled by the `depth` parameter. Avoids manual `imports = [...]` lists for leaf modules. + +### Impermanence +The host uses `impermanence` (ephemeral `/` via btrfs). Persistent paths must be explicitly declared in `hosts/mephistopheles/impermanence.nix`. + +### Secrets +Managed with `sops-nix`. Encrypted secrets live in `secrets/`. + +### Key Inputs +- **nvf** — Neovim configuration framework (used for all neovim config under `users/ilkecan/text-editors/neovim/`) +- **stylix** — System-wide theming +- **niri-flake** — Niri Wayland compositor +- **disko** — Declarative disk partitioning +- **impermanence** — Ephemeral root filesystem support +- **sops-nix** — Secrets management (encrypted secrets in `secrets/`) +- **dms** — DankMaterialShell, a desktop shell for Wayland compositors, built with Quickshell +- **betterfox-nix** — Firefox user.js optimization +- **git-hooks-nix** — Pre-commit hooks framework (deadnix, flake-checker, flint, gitleaks, nil, nixf-diagnose, ripsecrets) +- **nixos-cli** — NixOS CLI tool +- **mcp-servers-nix** — MCP server configuration for Home Manager +- **optnix** — Nix option analysis tool + +### Flake Module Outputs +Modules under `modules/` are exposed as flake outputs via `flake/modules.nix`: +- `flakeModules` — from `modules/flake/` +- `homeModules` — from `modules/home-manager/` +- `nixosModules` — from `modules/nixos/` + +Both host and user configurations dogfood their respective `*.default` module. + +### specialArgs / extraSpecialArgs +- NixOS modules receive: `inputs'`, `lib` (extended), `self'`, `userConfig` (the HM config) +- HM modules receive: `inputs'`, `self'`, `hostConfig` (the NixOS config), `osConfig` (alias for `hostConfig`) + +### Development Environment +The flake provides a `devShell` via direnv (`.envrc`) with pre-commit hooks enabled through `git-hooks-nix`. A CI app (`nix run .#ci`) wraps `nix-fast-build` for cached builds. A `trufflehog` flake check scans for leaked secrets. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 2b877d5..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,96 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## What This Is - -A NixOS + Home Manager configuration flake for one host (`mephistopheles`, a Lenovo ThinkPad E14 Gen7 Intel) and one user (`ilkecan`). Built with `flake-parts`. - -## Common Commands - -`nh` is configured with the flake path and used for all build/switch operations. The zellij layout (`.zellij-layout.kdl`) has dedicated panes for these: - -```bash -nh os switch # Rebuild and activate NixOS configuration -nh os repl # NixOS config REPL -nh home switch # Rebuild and activate Home Manager configuration -nh home repl # Home Manager config REPL -``` - -The raw `nix` CLI is used for flake-level operations: - -```bash -nix flake update [input] # Update flake inputs -nix flake metadata # Show input metadata -nix flake check # Check for evaluation errors -``` - -## Repository Structure - -``` -flake.nix # Entry point: delegates to flake-parts via ./flake -flake/ # Flake-parts modules defining all outputs - args/ # Generic flake-parts module dir for injecting custom args - # (currently only perSystem args, but not limited to that) - nixos-configurations.nix - home-configurations.nix - modules.nix -inputs/ # Applies patches to flake inputs - default.nix # Merges patched inputs over raw inputs - nixpkgs.nix # nixpkgs patches (module-level changes) - nixpkgs-patched.nix # nixpkgs-unstable patches (package-level changes) - home-manager.nix # home-manager patches - dms.nix # dms patches -lib/ # Custom lib extensions (lib.my.*) - my.nix # lib.my.importTree, lib.my.mkAbsolute - my-pkgs.nix # lib.my-pkgs.callExpression -hosts/mephistopheles/ # NixOS host configuration -users/ilkecan/ # Home Manager user configuration -modules/ # Reusable NixOS/HM/flake modules -packages/ # Custom pkgs instantiation (overlays applied here) -secrets/ # sops-nix encrypted secrets -``` - -## Key Architectural Patterns - -### Three nixpkgs Inputs - -There are three nixpkgs inputs with distinct purposes: - -- **`nixpkgs`** (stable, `nixos-25.11`) — base system. Patched in-place (overwrites itself in `inputs`) with **module-level** changes only (no package rebuilds). -- **`nixpkgs-unstable`** — always the original unpatched unstable channel. Exposed as `pkgs.unstable` overlay for select tools that need newer versions. -- **`nixpkgs-patched`** — patched version of `nixpkgs-unstable`, stored as a separate input. Used for **package-level** changes to contain cascade rebuilds: patching a package in `nixpkgs-unstable` directly could trigger rebuilds for all dependents; isolating it in a named input limits the blast radius to what explicitly uses `pkgs.patched`. - -### Input Patching -`inputs/default.nix` applies upstream PRs to inputs and makes patched versions transparent by overwriting the originals under `inputs.*` (except `nixpkgs-patched`, which is always a separate input). Modules consume patched inputs the same way as stock ones. - -### Custom pkgs Overlays -`packages/default.nix` instantiates nixpkgs with several overlays, making these package sets available everywhere: -- `pkgs.unstable` — nixos-unstable packages -- `pkgs.patched` — nixpkgs-unstable with package-level patches applied -- `pkgs.nur` — NUR packages -- `pkgs.notashelf` — packages from the flint flake -- `pkgs.llm-agents.*` — LLM agent tools - -### lib.my.importTree -Used extensively to auto-import directories. If a directory has a `default.nix`, that file is imported; otherwise all `.nix` files and subdirectories are imported recursively. Avoids manual `imports = [...]` lists for leaf modules. - -### Impermanence -The host uses `impermanence` (ephemeral `/` via btrfs). Persistent paths must be explicitly declared in `hosts/mephistopheles/impermanence.nix`. - -### Secrets -Managed with `sops-nix`. Encrypted secrets live in `secrets/`. - -### Key Inputs -- **nvf** — Neovim configuration framework (used for all neovim config under `users/ilkecan/text-editors/neovim/`) -- **stylix** — System-wide theming -- **niri-flake** — Niri Wayland compositor -- **disko** — Declarative disk partitioning -- **impermanence** — Ephemeral root filesystem support -- **sops-nix** — Secrets management (encrypted secrets in `secrets/`) -- **dms** — DankMaterialShell, a desktop shell for Wayland compositors, built with Quickshell -- **betterfox-nix** — Firefox user.js optimization - -### specialArgs / extraSpecialArgs -- NixOS modules receive: `inputs'`, `lib` (extended), `self'`, `homeConfig` (the HM config) -- HM modules receive: `inputs'`, `self'`, `osConfig` (the NixOS config) diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000..47dc3e3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file From 6c119c509adbae60157e6fc3fb114d373a1df238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Wed, 11 Mar 2026 00:14:24 +0300 Subject: [PATCH 17/21] hm.mcp: define `GITHUB_PERSONAL_ACCESS_TOKEN` --- hosts/mephistopheles/sops.nix | 2 +- secrets/users/ilkecan.yaml | 16 ++++++++++++++++ users/ilkecan/llm/mcp.nix | 3 ++- users/ilkecan/sops.nix | 16 +++++++++++++++- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/hosts/mephistopheles/sops.nix b/hosts/mephistopheles/sops.nix index 6305499..6dec3ac 100644 --- a/hosts/mephistopheles/sops.nix +++ b/hosts/mephistopheles/sops.nix @@ -22,7 +22,7 @@ in defaultSopsFile = "${self'}/secrets/hosts/${config.networking.hostName}.yaml"; secrets = { - github-access-token = {}; + github-access-token = { }; ilkecan-hashed-password = { neededForUsers = true; }; }; diff --git a/secrets/users/ilkecan.yaml b/secrets/users/ilkecan.yaml index e69de29..6362fc3 100644 --- a/secrets/users/ilkecan.yaml +++ b/secrets/users/ilkecan.yaml @@ -0,0 +1,16 @@ +github-access-token: ENC[AES256_GCM,data:xCAiYDXePGcMnb/3txPY8oxD4hXAgI2o/2vRsuruKznkRs2ReT256rnLODBSFfUbmn+CAPIrzfjysVFLjn5FYAAWcJqksexwKcvl4ww6byp2t+3JylMAhaxyFYRx,iv:MBqcpSPv1rA8uKdAt+RzMOWMA3K5yGof7DYT1LetxPc=,tag:JREvqnEdeYuUji1L7t2Pyw==,type:str] +sops: + age: + - recipient: age17fjhuectnh2t7jln7308jns0wawjfjt998gr64prl6qrztxfc5sspdyk7c + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZY203YVUyTTdyOWhvbEdH + Mm5SSUgwNzRwY3BsU2xYeFR0MjJid1NleURrCnhTaHcwSXZtcXB6aVV2cENQeEFn + NXR5V3dpa2pSNWNEcm9WM3RpTFpSTHMKLS0tIHV5b3J4bzJJam44WlR1R0V2dGNQ + N29CTHBUblFmZlU3VU11YkUxTlU0NmsKT8MdYf4x7gs9Apzvj0a9URh2M1NN0T+1 + mhu3aVFbB7pnSCGWIY/1mqxaYv5f68sq+T6GpSogY53aRYCyv5gGdA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2026-03-10T20:51:07Z" + mac: ENC[AES256_GCM,data:xZnRjz1QC+Vf1JKKvBmVhhdkW2VDybJc8qOSwIGZxxPMkvX1MoI1/1QHYayzBX9niWgmCTsC3HVLEo2/4QzTWPQHFX9sExaATydDtvSM5ik5tBwHYKIK/pU4zZW/REwGh8xcdu+9qFzGivFhtNTXxOcvE7vtHi9xEChgMwvOF5g=,iv:rwVZiNa92vD289K1HOiEpH7GaAMAkNM+2SCRfmUVdEA=,tag:N2enfnv4Ut//+B0g2g3xNA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.12.1 diff --git a/users/ilkecan/llm/mcp.nix b/users/ilkecan/llm/mcp.nix index 60f4961..e175d43 100644 --- a/users/ilkecan/llm/mcp.nix +++ b/users/ilkecan/llm/mcp.nix @@ -1,4 +1,5 @@ { + config, ... }: @@ -7,7 +8,7 @@ mcp-servers.programs = { fetch.enable = true; git.enable = true; - github.enable = true; + github = { enable = true; envFile = config.sops.templates.github-mpc-server-env.path; }; memory.enable = true; nixos.enable = true; sequential-thinking.enable = true; diff --git a/users/ilkecan/sops.nix b/users/ilkecan/sops.nix index ad7c571..15cc1ab 100644 --- a/users/ilkecan/sops.nix +++ b/users/ilkecan/sops.nix @@ -4,14 +4,28 @@ ... }: +let + inherit (config.home) + homeDirectory + username + ; + cfg = config.sops; +in { sops = { - defaultSopsFile = "${self'}/secrets/users/${config.home.username}.yaml"; + age.keyFile = "${homeDirectory}/.config/sops/age/key.txt"; + defaultSopsFile = "${self'}/secrets/users/${username}.yaml"; secrets = { + github-access-token = { }; }; templates = { + github-mpc-server-env = { + content = '' + GITHUB_PERSONAL_ACCESS_TOKEN=${cfg.placeholder.github-access-token} + ''; + }; }; }; } From 0a068d7df2da27cba934f9f57cbfd2dbb2016928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Wed, 11 Mar 2026 00:14:59 +0300 Subject: [PATCH 18/21] package.unstable.nix-fast-build: update PR patch hash --- packages/nix-fast-build.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nix-fast-build.nix b/packages/nix-fast-build.nix index 968803f..00fbc79 100644 --- a/packages/nix-fast-build.nix +++ b/packages/nix-fast-build.nix @@ -14,7 +14,7 @@ nix-fast-build.overrideAttrs (prev: { (fetchpatch2 { name = "use-nix-build-subcommand.patch"; url = "https://patch-diff.githubusercontent.com/raw/Mic92/nix-fast-build/pull/301.patch"; - hash = "sha256-a6c0rq45Brr4JBe2ncqUQmJx3tmr6iqaMT3IwSOzleg="; + hash = "sha256-p6QXVDnXIU+smSGfR0BBkAAaGHZoEEvkTRJXIoqEGZs="; }) ]; }) From 64976ca5e8df62cdaff4d947033eb8ed82f9fd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Wed, 11 Mar 2026 01:50:19 +0300 Subject: [PATCH 19/21] hm.nvim: add `blame.nvim` plugin --- .../neovim/plugins/blame-nvim.nix | 32 +++++++++++++++++++ .../text-editors/neovim/plugins/default.nix | 1 + .../neovim/treesitter/context.nix | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 users/ilkecan/text-editors/neovim/plugins/blame-nvim.nix diff --git a/users/ilkecan/text-editors/neovim/plugins/blame-nvim.nix b/users/ilkecan/text-editors/neovim/plugins/blame-nvim.nix new file mode 100644 index 0000000..d8cae76 --- /dev/null +++ b/users/ilkecan/text-editors/neovim/plugins/blame-nvim.nix @@ -0,0 +1,32 @@ +# https://github.com/FabijanZulj/blame.nvim +{ + pkgs, + ... +}: + +{ + programs.nvf.settings.vim = { + extraPlugins = { + blame-nvim = { + package = pkgs.unstable.vimPlugins.blame-nvim; + setup = '' + require('blame').setup { + date_format = "%r", + format_fn = require("blame.formats.default_formats").date_message, + merge_consecutive = true, + } + ''; + }; + }; + + keymaps = [ + { + desc = "Toggle Git Blame"; + key = ""; + mode = [ "n" ]; + action = "vim.cmd.BlameToggle"; + lua = true; + } + ]; + }; +} diff --git a/users/ilkecan/text-editors/neovim/plugins/default.nix b/users/ilkecan/text-editors/neovim/plugins/default.nix index c4965cf..310cdcc 100644 --- a/users/ilkecan/text-editors/neovim/plugins/default.nix +++ b/users/ilkecan/text-editors/neovim/plugins/default.nix @@ -4,6 +4,7 @@ { imports = [ + ./blame-nvim.nix ./blink-cmp ./blink-indent.nix # ./blink-pairs.nix diff --git a/users/ilkecan/text-editors/neovim/treesitter/context.nix b/users/ilkecan/text-editors/neovim/treesitter/context.nix index ea252ab..254e039 100644 --- a/users/ilkecan/text-editors/neovim/treesitter/context.nix +++ b/users/ilkecan/text-editors/neovim/treesitter/context.nix @@ -15,7 +15,7 @@ keymaps = [ { desc = "Toggle TS context"; - key = ""; + key = ""; mode = [ "n" ]; action = ''function() vim.cmd.TSContext("toggle") end''; lua = true; From 994f2cc8a65bfdb246a81b3e6bf4815ffc55a263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Wed, 11 Mar 2026 01:50:59 +0300 Subject: [PATCH 20/21] hm.mcp: add `time` --- users/ilkecan/llm/mcp.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/users/ilkecan/llm/mcp.nix b/users/ilkecan/llm/mcp.nix index e175d43..226d4f0 100644 --- a/users/ilkecan/llm/mcp.nix +++ b/users/ilkecan/llm/mcp.nix @@ -14,6 +14,7 @@ sequential-thinking.enable = true; serena = { enable = true; context = "claude-code"; enableWebDashboard = true; }; terraform.enable = true; + time.enable = true; }; programs.mcp = { From ae4693692630d223d47ce3be44002c647be03489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lkecan=20Bozdo=C4=9Fan?= Date: Wed, 11 Mar 2026 01:54:49 +0300 Subject: [PATCH 21/21] hm.mcp: add `--project-from-cwd` flag to `serena` --- users/ilkecan/llm/mcp.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/ilkecan/llm/mcp.nix b/users/ilkecan/llm/mcp.nix index 226d4f0..e7ce817 100644 --- a/users/ilkecan/llm/mcp.nix +++ b/users/ilkecan/llm/mcp.nix @@ -12,7 +12,7 @@ memory.enable = true; nixos.enable = true; sequential-thinking.enable = true; - serena = { enable = true; context = "claude-code"; enableWebDashboard = true; }; + serena = { enable = true; args = [ "--project-from-cwd" ]; context = "claude-code"; enableWebDashboard = true; }; terraform.enable = true; time.enable = true; };