├── templates ├── gleam │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── haskell │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── java │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── kotlin │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── python │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── javascript │ ├── .envrc │ ├── flake.nix │ └── flake.lock ├── elixir │ ├── .envrc │ ├── flake.nix │ └── flake.lock └── default.nix ├── .envrc ├── home ├── nvim │ └── config │ │ └── lua │ │ ├── numb-config.lua │ │ ├── notify-config.lua │ │ ├── dressing-config.lua │ │ ├── autopairs-config.lua │ │ ├── rainbow-config.lua │ │ ├── alpha-config.lua │ │ ├── inc-rename-config.lua │ │ ├── glance-config.lua │ │ ├── fidget-config.lua │ │ ├── tiny-inline-diagnostic-config.lua │ │ ├── treesitter-context-config.lua │ │ ├── dropbar-config.lua │ │ ├── lightbulb-config.lua │ │ ├── surround-config.lua │ │ ├── outline-config.lua │ │ ├── indent-blankline-config.lua │ │ ├── blink-config.lua │ │ ├── telescope-config.lua │ │ ├── util.lua │ │ ├── comment-config.lua │ │ ├── settings.lua │ │ ├── nvim-tree-config.lua │ │ ├── bufferline-config.lua │ │ ├── claude-code-config.lua │ │ ├── flash-config.lua │ │ ├── trouble-config.lua │ │ ├── hover-config.lua │ │ ├── treesitter-config.lua │ │ ├── which-key-config.lua │ │ ├── catppuccin-config.lua │ │ ├── gitsigns-config.lua │ │ └── dap-config.lua ├── direnv │ └── default.nix ├── navi │ └── default.nix ├── eza │ └── default.nix ├── zoxide │ └── default.nix ├── secrets │ └── default.nix ├── nh │ └── default.nix ├── btop │ └── default.nix ├── yazi │ └── default.nix ├── claude-code │ ├── config │ │ ├── commands │ │ │ └── tasks │ │ │ │ ├── create_spec.md │ │ │ │ ├── idea.md │ │ │ │ ├── run_plan.md │ │ │ │ ├── create_plan.md │ │ │ │ └── create_plan_with_tdd.md │ │ ├── CLAUDE.md │ │ ├── agents │ │ │ ├── code-reviewer.md │ │ │ ├── systems-architect.md │ │ │ ├── code-debugger.md │ │ │ ├── performance-optimizer.md │ │ │ └── security-auditor.md │ │ └── statusline.sh │ └── default.nix ├── codex │ └── default.nix ├── fzf │ └── default.nix ├── jq │ └── default.nix ├── games │ └── default.nix ├── lazygit │ └── default.nix ├── bat │ └── default.nix ├── delta │ └── default.nix ├── ghostty │ └── default.nix ├── kitty │ └── default.nix ├── tmux │ └── default.nix ├── default.nix ├── gh │ └── default.nix └── git │ └── default.nix ├── linux ├── openssh │ └── default.nix ├── tailscale │ └── default.nix ├── adguardhome │ └── default.nix ├── unbound │ └── default.nix └── default.nix ├── secrets ├── flaggy_token.age ├── dns_tailscale_key.age ├── homelab_tailscale_key.age └── secrets.nix ├── backgrounds ├── nord-theme.png └── one-dark-theme.png ├── hosts ├── bootable-iso │ ├── home.nix │ └── configuration.nix ├── bootable-sd │ ├── home.nix │ └── configuration.nix ├── cicucci-dns │ ├── home.nix │ ├── hardware-configuration.nix │ └── configuration.nix ├── cicucci-builder │ ├── home.nix │ ├── hardware-configuration.nix │ ├── disko-config.nix │ └── configuration.nix ├── cicucci-homelab │ ├── home.nix │ ├── disko-config.nix │ ├── hardware-configuration.nix │ └── configuration.nix ├── work-laptop │ ├── home.nix │ └── configuration.nix ├── cicucci-desktop │ ├── home.nix │ └── configuration.nix ├── cicucci-laptop │ ├── home.nix │ └── configuration.nix └── cicucci-server │ ├── home.nix │ └── configuration.nix ├── .gitignore ├── pkgs ├── nix-cleanup │ ├── default.nix │ └── nix-cleanup.sh ├── claude-code │ ├── update.sh │ └── default.nix ├── catppuccin │ ├── bat │ │ └── default.nix │ ├── btop │ │ └── default.nix │ ├── yazi │ │ └── default.nix │ └── zsh-syntax-highlighting │ │ └── default.nix ├── vimPlugins │ ├── claudecode-nvim │ │ └── default.nix │ └── tiny-code-action-nvim │ │ └── default.nix ├── ccusage │ ├── package-lock.json │ └── default.nix ├── toast │ ├── oktoast │ │ └── default.nix │ ├── toast-services │ │ └── default.nix │ └── toastApiKeyHelper │ │ └── default.nix ├── homebridge │ └── default.nix ├── default.nix ├── homebridge-config-ui-x │ └── default.nix ├── codex │ └── default.nix └── kotlin-lsp │ └── default.nix ├── bootstrap ├── rpi3.nix ├── rpi4.nix └── rpi5.nix ├── darwin ├── system-defaults │ └── default.nix ├── system-packages │ └── default.nix ├── homebrew │ └── default.nix └── default.nix ├── installer └── system-installer.nix ├── AGENTS.md ├── claude ├── CLAUDE.md ├── testing-strategy.md └── fcis-architecture.md ├── CLAUDE.md └── README.md /templates/gleam/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /templates/haskell/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /templates/java/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /templates/kotlin/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /templates/python/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | eval "$shellHook" 3 | -------------------------------------------------------------------------------- /templates/javascript/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | -------------------------------------------------------------------------------- /templates/elixir/.envrc: -------------------------------------------------------------------------------- 1 | use_flake 2 | eval "$shellHook" 3 | -------------------------------------------------------------------------------- /home/nvim/config/lua/numb-config.lua: -------------------------------------------------------------------------------- 1 | require("numb").setup() 2 | -------------------------------------------------------------------------------- /home/nvim/config/lua/notify-config.lua: -------------------------------------------------------------------------------- 1 | require("notify").setup({}) 2 | -------------------------------------------------------------------------------- /home/nvim/config/lua/dressing-config.lua: -------------------------------------------------------------------------------- 1 | require("dressing").setup({}) 2 | -------------------------------------------------------------------------------- /linux/openssh/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.openssh.enable = true; 3 | } 4 | -------------------------------------------------------------------------------- /home/nvim/config/lua/autopairs-config.lua: -------------------------------------------------------------------------------- 1 | require("nvim-autopairs").setup({}) 2 | -------------------------------------------------------------------------------- /home/nvim/config/lua/rainbow-config.lua: -------------------------------------------------------------------------------- 1 | require("rainbow-delimiters.setup").setup({}) 2 | -------------------------------------------------------------------------------- /secrets/flaggy_token.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoda3/nix-configs/HEAD/secrets/flaggy_token.age -------------------------------------------------------------------------------- /backgrounds/nord-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoda3/nix-configs/HEAD/backgrounds/nord-theme.png -------------------------------------------------------------------------------- /home/nvim/config/lua/alpha-config.lua: -------------------------------------------------------------------------------- 1 | require("alpha").setup(require("alpha.themes.dashboard").config) 2 | -------------------------------------------------------------------------------- /hosts/bootable-iso/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { }; 7 | } 8 | -------------------------------------------------------------------------------- /hosts/bootable-sd/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { }; 7 | } 8 | -------------------------------------------------------------------------------- /hosts/cicucci-dns/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { }; 7 | } 8 | -------------------------------------------------------------------------------- /secrets/dns_tailscale_key.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoda3/nix-configs/HEAD/secrets/dns_tailscale_key.age -------------------------------------------------------------------------------- /backgrounds/one-dark-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoda3/nix-configs/HEAD/backgrounds/one-dark-theme.png -------------------------------------------------------------------------------- /hosts/cicucci-builder/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { }; 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .direnv 2 | .vscode 3 | .nix-mix 4 | .pre-commit-config.yaml 5 | result 6 | .aider* 7 | .env 8 | .claude 9 | -------------------------------------------------------------------------------- /home/nvim/config/lua/inc-rename-config.lua: -------------------------------------------------------------------------------- 1 | require("inc_rename").setup({ 2 | input_buffer_type = "dressing", 3 | }) 4 | -------------------------------------------------------------------------------- /secrets/homelab_tailscale_key.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fmoda3/nix-configs/HEAD/secrets/homelab_tailscale_key.age -------------------------------------------------------------------------------- /home/direnv/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.direnv = { 3 | enable = true; 4 | nix-direnv.enable = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /home/navi/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.navi = { 3 | enable = true; 4 | enableZshIntegration = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /home/eza/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.eza = { 3 | enable = true; 4 | icons = "auto"; 5 | git = true; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /home/zoxide/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.zoxide = { 3 | enable = true; 4 | enableZshIntegration = true; 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /home/nvim/config/lua/glance-config.lua: -------------------------------------------------------------------------------- 1 | require("glance").setup({ 2 | border = { 3 | enable = true, 4 | top_char = "─", 5 | bottom_char = "─", 6 | }, 7 | }) 8 | -------------------------------------------------------------------------------- /hosts/cicucci-homelab/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { 7 | includeFonts = true; 8 | useNeovim = true; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /home/nvim/config/lua/fidget-config.lua: -------------------------------------------------------------------------------- 1 | -- Setup fidget for displaying LSP messages 2 | require("fidget").setup({ 3 | notification = { 4 | window = { 5 | winblend = 0, 6 | }, 7 | }, 8 | }) 9 | -------------------------------------------------------------------------------- /hosts/work-laptop/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { 7 | includeFonts = true; 8 | useNeovim = true; 9 | isWork = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /home/nvim/config/lua/tiny-inline-diagnostic-config.lua: -------------------------------------------------------------------------------- 1 | require("tiny-inline-diagnostic").setup({ 2 | options = { 3 | multilines = { 4 | enabled = true, 5 | always_show = true, 6 | }, 7 | }, 8 | }) 9 | -------------------------------------------------------------------------------- /hosts/cicucci-desktop/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { 7 | includeFonts = true; 8 | useNeovim = true; 9 | includeGames = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /hosts/cicucci-laptop/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { 7 | includeFonts = true; 8 | useNeovim = true; 9 | includeGames = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /hosts/cicucci-server/home.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../home 4 | ]; 5 | 6 | my-home = { 7 | includeFonts = true; 8 | useNeovim = true; 9 | includeGames = true; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /home/secrets/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | with lib; 3 | let 4 | cfg = config.my-home; 5 | in 6 | { 7 | age.secrets = { 8 | # Work machine secrets 9 | flaggy_token = mkIf cfg.isWork { 10 | file = ../../secrets/flaggy_token.age; 11 | }; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /home/nh/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | { 3 | programs.nh = { 4 | enable = true; 5 | } // lib.optionalAttrs pkgs.stdenv.isDarwin { 6 | darwinFlake = config.my-home.flake; 7 | } // lib.optionalAttrs pkgs.stdenv.isLinux { 8 | osFlake = config.my-home.flake; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /hosts/cicucci-server/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../darwin 4 | ]; 5 | 6 | my-darwin = { 7 | isServer = true; 8 | }; 9 | 10 | # Used for backwards compatibility, please read the changelog before changing. 11 | # $ darwin-rebuild changelog 12 | system.stateVersion = 6; 13 | } 14 | -------------------------------------------------------------------------------- /home/btop/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.btop = { 4 | enable = true; 5 | settings = { 6 | color_theme = "catppuccin-frappe"; 7 | }; 8 | themes = { 9 | catppuccin-frappe = builtins.readFile "${pkgs.catppuccin.btop}/themes/catppuccin_frappe.theme"; 10 | }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /hosts/cicucci-desktop/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../darwin 4 | ]; 5 | 6 | my-darwin = { 7 | enableSudoTouch = true; 8 | }; 9 | 10 | # Used for backwards compatibility, please read the changelog before changing. 11 | # $ darwin-rebuild changelog 12 | system.stateVersion = 6; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/cicucci-laptop/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../darwin 4 | ]; 5 | 6 | my-darwin = { 7 | enableSudoTouch = true; 8 | }; 9 | 10 | # Used for backwards compatibility, please read the changelog before changing. 11 | # $ darwin-rebuild changelog 12 | system.stateVersion = 4; 13 | } 14 | -------------------------------------------------------------------------------- /hosts/work-laptop/configuration.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../darwin 4 | ]; 5 | 6 | my-darwin = { 7 | isWork = true; 8 | enableSudoTouch = true; 9 | }; 10 | 11 | # Used for backwards compatibility, please read the changelog before changing. 12 | # $ darwin-rebuild changelog 13 | system.stateVersion = 4; 14 | } 15 | -------------------------------------------------------------------------------- /home/nvim/config/lua/treesitter-context-config.lua: -------------------------------------------------------------------------------- 1 | require("treesitter-context").setup({}) 2 | 3 | require("which-key").add({ 4 | { 5 | "jc", 6 | function() 7 | require("treesitter-context").go_to_context(vim.v.count1) 8 | end, 9 | mode = { "n" }, 10 | desc = "Jump to Context", 11 | icon = "󰆷", 12 | silent = true, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /home/nvim/config/lua/dropbar-config.lua: -------------------------------------------------------------------------------- 1 | local dropbar_api = require("dropbar.api") 2 | require("which-key").add({ 3 | { ";", dropbar_api.pick, desc = "Pick symbols in winbar", icon = "" }, 4 | { "[;", dropbar_api.goto_context_start, desc = "Go to start of current context", icon = "󰆸" }, 5 | { "];", dropbar_api.select_next_context, desc = "Select next context", icon = "󰆹" }, 6 | }) 7 | -------------------------------------------------------------------------------- /pkgs/nix-cleanup/default.nix: -------------------------------------------------------------------------------- 1 | { writeShellApplication 2 | , lib 3 | , stdenv 4 | , replaceVars 5 | , coreutils 6 | , gawk 7 | , gnugrep 8 | , nix 9 | }: 10 | writeShellApplication { 11 | name = "nix-cleanup"; 12 | 13 | text = lib.readFile (replaceVars ./nix-cleanup.sh { 14 | isNixOS = if stdenv.isLinux then "1" else "0"; 15 | }); 16 | 17 | runtimeInputs = [ coreutils gawk gnugrep nix ]; 18 | } 19 | -------------------------------------------------------------------------------- /home/yazi/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.yazi = { 4 | enable = true; 5 | enableZshIntegration = true; 6 | }; 7 | 8 | xdg.configFile = { 9 | "yazi/theme.toml".source = 10 | "${pkgs.catppuccin.yazi}/frappe/catppuccin-frappe-blue.toml"; 11 | 12 | "yazi/Catppuccin-frappe.tmTheme".source = 13 | "${pkgs.catppuccin.bat}/Catppuccin Frappe.tmTheme"; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /home/claude-code/config/commands/tasks/create_spec.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Create a specification 3 | --- 4 | 5 | Now that we’ve wrapped up the brainstorming process, can you compile our findings into a comprehensive, developer-ready specification? Include all relevant requirements, architecture choices, data handling details, error handling strategies, and a testing plan so a developer can immediately begin implementation. 6 | 7 | -------------------------------------------------------------------------------- /home/nvim/config/lua/lightbulb-config.lua: -------------------------------------------------------------------------------- 1 | -- Setup lightbulb sign to indicate a code action is available 2 | vim.cmd([[autocmd CursorHold,CursorHoldI * lua require'nvim-lightbulb'.update_lightbulb()]]) 3 | 4 | -- Change to yellow lightbulb icon 5 | util.colorize({ 6 | LightBulbSignColor = { fg = colors.yellow }, 7 | }) 8 | vim.fn.sign_define("LightBulbSign", { text = "", texthl = "LightBulbSignColor", linehl = "", numhl = "" }) 9 | -------------------------------------------------------------------------------- /home/nvim/config/lua/surround-config.lua: -------------------------------------------------------------------------------- 1 | require("nvim-surround").setup({ 2 | highlight = { 3 | duration = 200, 4 | }, 5 | }) 6 | 7 | -- Register surround help with which-key 8 | require("which-key").add({ 9 | { "ys", group = "Surround (add)", icon = "󰅪" }, 10 | { "cs", group = "Surround (change)", icon = "󰛔" }, 11 | { "ds", group = "Surround (delete)", icon = "󱟁" }, 12 | { "S", group = "Surround (visual)", icon = "󰒉", mode = "v" }, 13 | }) 14 | -------------------------------------------------------------------------------- /pkgs/claude-code/update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env nix-shell 2 | #!nix-shell --pure --keep NIX_PATH -i bash --packages nodejs nix-update git 3 | 4 | set -euo pipefail 5 | 6 | version=$(npm view @anthropic-ai/claude-code version) 7 | 8 | # Update version and hashes 9 | AUTHORIZED=1 NIXPKGS_ALLOW_UNFREE=1 nix-update claude-code --version="$version" --generate-lockfile 10 | nix-update vscode-extensions.anthropic.claude-code --use-update-script --version "$version" 11 | -------------------------------------------------------------------------------- /home/nvim/config/lua/outline-config.lua: -------------------------------------------------------------------------------- 1 | require("outline").setup({ 2 | outline_window = { 3 | auto_jump = true, 4 | focus_on_open = false, 5 | }, 6 | }) 7 | 8 | -- Register outline keybindings with which-key 9 | require("which-key").add({ 10 | { "o", group = "Outline", icon = "󰙅" }, 11 | { "oo", "Outline", desc = "Toggle outline", icon = "󰔡" }, 12 | { "oO", "OutlineOpen", desc = "Open outline", icon = "󰏋" }, 13 | }) 14 | -------------------------------------------------------------------------------- /home/claude-code/config/commands/tasks/idea.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Idea Honing 3 | --- 4 | 5 | Ask me one question at a time so we can develop a thorough, step-by-step spec for this idea. Each question should build on my previous answers, and our end goal is to have a detailed specification I can hand off to a developer. Let’s do this iteratively and dig into every relevant detail. Remember, only one question at a time. 6 | 7 | Here’s the idea: 8 | 9 | #$ARGUMENTS 10 | 11 | -------------------------------------------------------------------------------- /linux/tailscale/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | with lib; 3 | let 4 | advertiseExitNode = optionals config.my-linux.tailscale.advertiseExitNode [ "--advertise-exit-node" ]; 5 | in 6 | { 7 | config = mkIf config.my-linux.tailscale.enable { 8 | services.tailscale = { 9 | enable = true; 10 | useRoutingFeatures = "both"; 11 | authKeyFile = config.my-linux.tailscale.authkey; 12 | extraUpFlags = advertiseExitNode; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /hosts/bootable-iso/configuration.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: { 2 | boot.kernelPackages = pkgs.linuxPackages; 3 | 4 | imports = [ 5 | ../../linux 6 | ]; 7 | 8 | time.timeZone = "America/New_York"; 9 | 10 | i18n.defaultLocale = "en_US.UTF-8"; 11 | 12 | # Lots of stuff that uses aarch64 that claims doesn't work, but actually works. 13 | nixpkgs.config = { 14 | allowUnfree = true; 15 | allowUnsupportedSystem = true; 16 | }; 17 | 18 | my-linux = { }; 19 | } 20 | -------------------------------------------------------------------------------- /home/nvim/config/lua/indent-blankline-config.lua: -------------------------------------------------------------------------------- 1 | local highlight = { 2 | "RainbowDelimiterRed", 3 | "RainbowDelimiterYellow", 4 | "RainbowDelimiterBlue", 5 | "RainbowDelimiterOrange", 6 | "RainbowDelimiterGreen", 7 | "RainbowDelimiterViolet", 8 | "RainbowDelimiterCyan", 9 | } 10 | local hooks = require("ibl.hooks") 11 | require("ibl").setup({ 12 | scope = { highlight = highlight }, 13 | }) 14 | hooks.register(hooks.type.SCOPE_HIGHLIGHT, hooks.builtin.scope_highlight_from_extmark) 15 | -------------------------------------------------------------------------------- /pkgs/catppuccin/bat/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , fetchFromGitHub 3 | }: 4 | stdenv.mkDerivation { 5 | pname = "catppuccin-bat"; 6 | version = "2025-06-29"; 7 | 8 | src = fetchFromGitHub { 9 | owner = "catppuccin"; 10 | repo = "bat"; 11 | rev = "6810349b28055dce54076712fc05fc68da4b8ec0"; 12 | sha256 = "sha256-lJapSgRVENTrbmpVyn+UQabC9fpV1G1e+CdlJ090uvg="; 13 | }; 14 | 15 | installPhase = '' 16 | mkdir -p $out/themes 17 | cp themes/* $out/themes 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /pkgs/catppuccin/btop/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , fetchFromGitHub 3 | }: 4 | stdenv.mkDerivation { 5 | pname = "catppuccin-btop"; 6 | version = "2024-09-23"; 7 | 8 | src = fetchFromGitHub { 9 | owner = "catppuccin"; 10 | repo = "btop"; 11 | rev = "f437574b600f1c6d932627050b15ff5153b58fa3"; 12 | sha256 = "sha256-mEGZwScVPWGu+Vbtddc/sJ+mNdD2kKienGZVUcTSl+c="; 13 | }; 14 | 15 | installPhase = '' 16 | mkdir -p $out/themes 17 | cp themes/* $out/themes 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /home/codex/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.codex = { 3 | enable = true; 4 | settings = { 5 | rmcp_client = true; 6 | mcp_servers = { 7 | context7 = { 8 | url = "https://mcp.context7.com/mcp"; 9 | }; 10 | deepwiki = { 11 | url = "https://mcp.deepwiki.com/mcp"; 12 | }; 13 | sequential-thinking = { 14 | url = "https://remote.mcpservers.org/sequentialthinking/mcp"; 15 | }; 16 | }; 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /pkgs/catppuccin/yazi/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , fetchFromGitHub 3 | }: 4 | stdenv.mkDerivation { 5 | pname = "catppuccin-yazi"; 6 | version = "2025-08-06"; 7 | 8 | src = fetchFromGitHub { 9 | owner = "catppuccin"; 10 | repo = "yazi"; 11 | rev = "043ffae14e7f7fcc136636d5f2c617b5bc2f5e31"; 12 | sha256 = "sha256-zkL46h1+U9ThD4xXkv1uuddrlQviEQD3wNZFRgv7M8Y="; 13 | }; 14 | 15 | installPhase = '' 16 | mkdir -p $out/themes 17 | cp -r themes/* $out/themes 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /bootstrap/rpi3.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | # nixos-generate-config should normally set up file systems correctly 4 | imports = [ 5 | "${fetchTarball "https://github.com/NixOS/nixos-hardware/archive/master.tar.gz" }/raspberry-pi/3" 6 | ./hardware-configuration.nix 7 | ]; 8 | 9 | swapDevices = [{ device = "/swapfile"; size = 2048; }]; 10 | 11 | environment.systemPackages = with pkgs; [ vim git ]; 12 | 13 | services.openssh.enable = true; 14 | 15 | system.stateVersion = "24.11"; 16 | } 17 | -------------------------------------------------------------------------------- /bootstrap/rpi4.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | # nixos-generate-config should normally set up file systems correctly 4 | imports = [ 5 | "${fetchTarball "https://github.com/NixOS/nixos-hardware/archive/master.tar.gz" }/raspberry-pi/4" 6 | ./hardware-configuration.nix 7 | ]; 8 | 9 | swapDevices = [{ device = "/swapfile"; size = 2048; }]; 10 | 11 | environment.systemPackages = with pkgs; [ vim git ]; 12 | 13 | services.openssh.enable = true; 14 | 15 | system.stateVersion = "24.11"; 16 | } 17 | -------------------------------------------------------------------------------- /bootstrap/rpi5.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | # nixos-generate-config should normally set up file systems correctly 4 | imports = [ 5 | "${fetchTarball "https://github.com/NixOS/nixos-hardware/archive/master.tar.gz" }/raspberry-pi/5" 6 | ./hardware-configuration.nix 7 | ]; 8 | 9 | swapDevices = [{ device = "/swapfile"; size = 2048; }]; 10 | 11 | environment.systemPackages = with pkgs; [ vim git ]; 12 | 13 | services.openssh.enable = true; 14 | 15 | system.stateVersion = "24.11"; 16 | } 17 | -------------------------------------------------------------------------------- /hosts/bootable-sd/configuration.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | boot = { 4 | kernelPackages = pkgs.linuxPackages; 5 | loader = { 6 | grub.enable = false; 7 | generic-extlinux-compatible.enable = true; 8 | }; 9 | }; 10 | 11 | imports = [ 12 | ../../linux 13 | ]; 14 | 15 | time.timeZone = "America/New_York"; 16 | 17 | i18n.defaultLocale = "en_US.UTF-8"; 18 | 19 | nixpkgs.config = { 20 | allowUnfree = true; 21 | allowUnsupportedSystem = true; 22 | }; 23 | 24 | my-linux = { }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /pkgs/vimPlugins/claudecode-nvim/default.nix: -------------------------------------------------------------------------------- 1 | { fetchFromGitHub 2 | , vimUtils 3 | , vimPlugins 4 | }: 5 | vimUtils.buildVimPlugin { 6 | pname = "claudecode-nvim"; 7 | version = "2025-12-09"; 8 | src = fetchFromGitHub { 9 | owner = "coder"; 10 | repo = "claudecode.nvim"; 11 | rev = "6091df0e8edcdc92526cec23bbb42f63c0bb5ff2"; 12 | sha256 = "sha256-PmSYIE7j9C2ckJc9wDIm4KCozXP0z1U9TOdItnDyoDQ="; 13 | }; 14 | dependencies = [ vimPlugins.snacks-nvim ]; 15 | meta.homepage = "https://github.com/coder/claudecode.nvim/"; 16 | } 17 | -------------------------------------------------------------------------------- /pkgs/catppuccin/zsh-syntax-highlighting/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , fetchFromGitHub 3 | }: 4 | stdenv.mkDerivation { 5 | pname = "catppuccin-zsh-syntax-highlighting"; 6 | version = "2024-07-20"; 7 | 8 | src = fetchFromGitHub { 9 | owner = "catppuccin"; 10 | repo = "zsh-syntax-highlighting"; 11 | rev = "7926c3d3e17d26b3779851a2255b95ee650bd928"; 12 | sha256 = "sha256-l6tztApzYpQ2/CiKuLBf8vI2imM6vPJuFdNDSEi7T/o="; 13 | }; 14 | 15 | installPhase = '' 16 | mkdir -p $out/themes 17 | cp themes/* $out/themes 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /home/fzf/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.fzf = { 3 | enable = true; 4 | enableZshIntegration = true; 5 | # Has Catppuccin theme support 6 | colors = { 7 | # Catppuccin Frappe colors 8 | "bg+" = "#414559"; 9 | "bg" = "#303446"; 10 | "spinner" = "#f2d5cf"; 11 | "hl" = "#e78284"; 12 | "fg" = "#c6d0f5"; 13 | "header" = "#e78284"; 14 | "info" = "#ca9ee6"; 15 | "pointer" = "#f2d5cf"; 16 | "marker" = "#f2d5cf"; 17 | "fg+" = "#c6d0f5"; 18 | "prompt" = "#ca9ee6"; 19 | "hl+" = "#e78284"; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /home/nvim/config/lua/blink-config.lua: -------------------------------------------------------------------------------- 1 | require("blink.cmp").setup({ 2 | fuzzy = { 3 | implementation = "lua", 4 | prebuilt_binaries = { 5 | download = false, 6 | }, 7 | }, 8 | keymap = { 9 | preset = "super-tab", 10 | }, 11 | completion = { 12 | list = { 13 | selection = { 14 | preselect = function(ctx) 15 | return not require("blink.cmp").snippet_active({ direction = 1 }) 16 | end, 17 | }, 18 | }, 19 | }, 20 | signature = { 21 | enabled = true, 22 | window = { 23 | show_documentation = true, 24 | }, 25 | }, 26 | }) 27 | require("blink.cmp.fuzzy").set_implementation("rust") 28 | -------------------------------------------------------------------------------- /home/jq/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.jq = { 3 | enable = true; 4 | colors = { 5 | null = "2;37"; # Dim white - subtle like Frappe overlay colors 6 | false = "0;31"; # Red - Frappe red #e78284 7 | true = "0;32"; # Green - Frappe green #a6d189 8 | numbers = "0;33"; # Yellow - Frappe yellow #e5c890 9 | strings = "0;36"; # Cyan - representing Frappe teal #81c8be 10 | arrays = "1;34"; # Bright blue - Frappe blue #8caaee 11 | objects = "1;37"; # Bright white - Frappe text color #c6d0f5 12 | objectKeys = "1;35"; # Bright magenta - Frappe mauve #ca9ee6 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /pkgs/vimPlugins/tiny-code-action-nvim/default.nix: -------------------------------------------------------------------------------- 1 | { fetchFromGitHub 2 | , vimUtils 3 | , vimPlugins 4 | }: 5 | vimUtils.buildVimPlugin { 6 | pname = "tiny-code-action-nvim"; 7 | version = "2025-12-17"; 8 | src = fetchFromGitHub { 9 | owner = "rachartier"; 10 | repo = "tiny-code-action.nvim"; 11 | rev = "0932b80d4de8d1c9c860536d21eff165aa0ced13"; 12 | sha256 = "sha256-zNOfgdYFx3fLplvjmrlw7RZRH1WPIgz4i6zDfBJPhak="; 13 | }; 14 | dependencies = [ vimPlugins.plenary-nvim ]; 15 | nvimSkipModules = [ 16 | "tiny-code-action.previewers.snacks" 17 | ]; 18 | meta.homepage = "https://github.com/rachartier/tiny-code-action.nvim/"; 19 | } 20 | -------------------------------------------------------------------------------- /home/games/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | with lib; 3 | let 4 | dwarf-fortress-package = if pkgs.stdenv.isDarwin then pkgs.pkgsx86_64Darwin.dwarf-fortress else pkgs.dwarf-fortress; 5 | dwarf-fortress-custom = dwarf-fortress-package.override { 6 | theme = "mayday"; 7 | enableSoundSense = true; 8 | }; 9 | in 10 | { 11 | config = mkIf config.my-home.includeGames { 12 | home = { 13 | packages = with pkgs; [ 14 | # dwarf-fortress-custom 15 | freesweep 16 | # gnuchess 17 | nethack 18 | ninvaders 19 | nudoku 20 | pacvim 21 | rogue 22 | ]; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /home/lazygit/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.lazygit = { 3 | enable = true; 4 | settings = { 5 | theme = { 6 | activeBorderColor = [ "#1e66f5" "bold" ]; 7 | inactiveBorderColor = [ "#6c6f85" ]; 8 | optionsTextColor = [ "#1e66f5" ]; 9 | selectedLineBgColor = [ "#ccd0da" ]; 10 | cherryPickedCommitBgColor = [ "#bcc0cc" ]; 11 | cherryPickedCommitFgColor = [ "#1e66f5" ]; 12 | unstagedChangesColor = [ "#d20f39" ]; 13 | defaultFgColor = [ "#4c4f69" ]; 14 | searchingActiveBorderColor = [ "#df8e1d" ]; 15 | }; 16 | authorColors = { 17 | "*" = "#7287fd"; 18 | }; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /hosts/cicucci-builder/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { 5 | imports = [ 6 | ./disko-config.nix 7 | ]; 8 | 9 | boot = { 10 | loader.grub = { 11 | device = "nodev"; 12 | efiSupport = true; 13 | efiInstallAsRemovable = true; 14 | }; 15 | initrd = { 16 | availableKernelModules = [ "ahci" "xhci_pci" "nvme" "usbhid" "sr_mod" ]; 17 | kernelModules = [ ]; 18 | }; 19 | kernelModules = [ ]; 20 | extraModulePackages = [ ]; 21 | growPartition = true; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /templates/haskell/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example Haskell Project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, ... }: { 13 | devShells.default = pkgs.haskellPackages.shellFor { 14 | packages = p: [ ]; 15 | 16 | buildInputs = with pkgs.haskellPackages; [ cabal-install ghcid ]; 17 | 18 | withHoogle = true; 19 | }; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /home/claude-code/config/commands/tasks/run_plan.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Run a plan 3 | --- 4 | 5 | 1. Open #$ARGUMENTS and identify any prompts not marked as completed. 6 | 2. For each incomplete prompt: 7 | - Double-check if it's truly unfinished (if uncertain, ask for clarification). 8 | - If you confirm it's already done, skip it. 9 | - Otherwise, implement it as described. 10 | - Make sure the tests pass, and the program builds/runs 11 | - Commit the changes to your repository with a clear commit message. 12 | - Update #$ARGUMENTS to mark this prompt as completed. 13 | 3. After you finish each prompt, pause and wait for user review or feedback. 14 | 4. Repeat with the next unfinished prompt as directed by the user. 15 | 16 | -------------------------------------------------------------------------------- /templates/javascript/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example JavaScript/TypeScript project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, ... }: { 13 | devShells.default = pkgs.mkShell { 14 | packages = with pkgs; [ 15 | yarn 16 | # Can override node version 17 | # (yarn.override { nodejs = nodejs-12_x; }) 18 | ]; 19 | }; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /home/nvim/config/lua/telescope-config.lua: -------------------------------------------------------------------------------- 1 | -- Telescope Settings 2 | require("which-key").add({ 3 | { "f", group = "Find", icon = "󰍉" }, 4 | { 5 | "ff", 6 | require("telescope.builtin").find_files, 7 | desc = "Telescope: Find files", 8 | icon = "󰈞", 9 | noremap = true, 10 | }, 11 | { 12 | "fg", 13 | require("telescope.builtin").live_grep, 14 | desc = "Telescope: Live grep", 15 | icon = "󰊄", 16 | noremap = true, 17 | }, 18 | { "fb", require("telescope.builtin").buffers, desc = "Telescope: Buffers", icon = "󰕘", noremap = true }, 19 | { 20 | "fh", 21 | require("telescope.builtin").help_tags, 22 | desc = "Telescope: Help tags", 23 | icon = "󰋖", 24 | noremap = true, 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /templates/gleam/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example Gleam Project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, ... }: 13 | let 14 | inputs = with pkgs; [ 15 | erlang 16 | gleam 17 | rebar3 18 | ]; 19 | in 20 | { 21 | devShells.default = pkgs.mkShell { 22 | packages = inputs; 23 | }; 24 | }; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /darwin/system-defaults/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | system.keyboard = { 3 | enableKeyMapping = true; 4 | remapCapsLockToControl = true; 5 | }; 6 | 7 | system.defaults = { 8 | # dock = { 9 | # orientation = "bottom"; 10 | # showhidden = true; 11 | # mineffect = "genie"; 12 | # minimize-to-application = true; 13 | # launchanim = true; 14 | # show-process-indicators = true; 15 | # # tilesize = 48; 16 | # mru-spaces = true; 17 | # }; 18 | finder = { 19 | # AppleShowAllExtensions = true; 20 | # FXEnableExtensionChangeWarning = false; 21 | # CreateDesktop = false; # disable desktop icons 22 | }; 23 | NSGlobalDomain = { 24 | AppleInterfaceStyle = "Dark"; # set dark mode 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /home/nvim/config/lua/util.lua: -------------------------------------------------------------------------------- 1 | local util = {} 2 | -- Go trough the table and highlight the group with the color values 3 | util.highlight = function(group, color) 4 | local style = color.style and "gui=" .. color.style or "gui=NONE" 5 | local fg = color.fg and "guifg=" .. color.fg or "guifg=NONE" 6 | local bg = color.bg and "guibg=" .. color.bg or "guibg=NONE" 7 | local sp = color.sp and "guisp=" .. color.sp or "" 8 | 9 | local hl = "highlight " .. group .. " " .. style .. " " .. fg .. " " .. bg .. " " .. sp 10 | 11 | vim.cmd(hl) 12 | if color.link then 13 | vim.cmd("highlight! link " .. group .. " " .. color.link) 14 | end 15 | end 16 | 17 | util.colorize = function(color_groups) 18 | for group, colors in pairs(color_groups) do 19 | util.highlight(group, colors) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /pkgs/ccusage/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ccusage", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "ccusage": "^17.2.0" 9 | } 10 | }, 11 | "node_modules/ccusage": { 12 | "version": "17.2.0", 13 | "resolved": "https://registry.npmjs.org/ccusage/-/ccusage-17.2.0.tgz", 14 | "integrity": "sha512-drWnQz/V27w00eHsEKD1DMKhWPTS2S+gPGynteKvdrcvSHeilzcN4d7uOPADR4c32oBlciBaBKSG5zWD1zha1A==", 15 | "license": "MIT", 16 | "bin": { 17 | "ccusage": "dist/index.js" 18 | }, 19 | "engines": { 20 | "node": ">=20.19.4" 21 | }, 22 | "funding": { 23 | "url": "https://github.com/ryoppippi/ccusage?sponsor=1" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /templates/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | elixir = { 3 | path = ./elixir; 4 | description = "Elixir project setup with mix"; 5 | }; 6 | gleam = { 7 | path = ./gleam; 8 | description = "Gleam project setup"; 9 | }; 10 | haskell = { 11 | path = ./haskell; 12 | description = "Haskell project setup with cabal"; 13 | }; 14 | java = { 15 | path = ./java; 16 | description = "Java project setup with gradle or maven"; 17 | }; 18 | javascript = { 19 | path = ./javascript; 20 | description = "Javascript project setup with yarn"; 21 | }; 22 | kotlin = { 23 | path = ./kotlin; 24 | description = "Kotlin project setup with gradle"; 25 | }; 26 | python = { 27 | path = ./python; 28 | description = "Python project setup with virtualenv"; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /darwin/system-packages/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | let 3 | extensions = (with pkgs.vscode-extensions; [ 4 | bbenoist.nix 5 | ]) ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [ 6 | { 7 | name = "nord-visual-studio-code"; 8 | publisher = "arcticicestudio"; 9 | version = "0.19.0"; 10 | sha256 = "05bmzrmkw9syv2wxqlfddc3phjads6ql2grknws85fcqzqbfl1kb"; 11 | } 12 | { 13 | name = "vscode-theme-onedark"; 14 | publisher = "akamud"; 15 | version = "2.2.3"; 16 | sha256 = "1m6f6p7x8vshhb03ml7sra3v01a7i2p3064mvza800af7cyj3w5m"; 17 | } 18 | ]; 19 | vscode-with-extensions = pkgs.vscode-with-extensions.override { 20 | vscodeExtensions = extensions; 21 | }; 22 | in 23 | { 24 | environment.systemPackages = [ 25 | pkgs.kitty 26 | vscode-with-extensions 27 | ]; 28 | } 29 | -------------------------------------------------------------------------------- /home/bat/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.bat = { 4 | enable = true; 5 | config = { 6 | theme = "catppuccin-frappe"; 7 | }; 8 | extraPackages = with pkgs.bat-extras; [ batdiff batman batgrep batwatch ]; 9 | themes = { 10 | catppuccin-frappe = { 11 | src = pkgs.catppuccin.bat; 12 | file = "themes/Catppuccin Frappe.tmTheme"; 13 | }; 14 | catppuccin-latte = { 15 | src = pkgs.catppuccin.bat; 16 | file = "themes/Catppuccin Latte.tmTheme"; 17 | }; 18 | catppuccin-macchiato = { 19 | src = pkgs.catppuccin.bat; 20 | file = "themes/Catppuccin Macchiato.tmTheme"; 21 | }; 22 | catppuccin-mocha = { 23 | src = pkgs.catppuccin.bat; 24 | file = "themes/Catppuccin Mocha.tmTheme"; 25 | }; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /pkgs/toast/oktoast/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , lib 3 | , makeWrapper 4 | , writeShellScriptBin 5 | , saml2aws 6 | , gnused 7 | , awscli 8 | }: 9 | stdenv.mkDerivation { 10 | pname = "oktoast"; 11 | version = "1.0"; 12 | 13 | src = fetchGit { 14 | url = "git@github.toasttab.com:toasttab/oktoast-setup.git"; 15 | rev = "293677eb5d5c2ac928fe127ae8b990d7c499fc4a"; 16 | }; 17 | 18 | nativeBuildInputs = [ 19 | makeWrapper 20 | ]; 21 | 22 | installPhase = '' 23 | mkdir -p $out/bin 24 | cp oktoast $out/bin 25 | ''; 26 | 27 | postFixup = '' 28 | wrapProgram $out/bin/oktoast \ 29 | --prefix PATH : ${lib.makeBinPath [ 30 | saml2aws 31 | # gnused installs "sed", but oktoast needs "gsed" 32 | (writeShellScriptBin "gsed" "exec -a $0 ${gnused}/bin/sed \"$@\"") 33 | awscli 34 | ]} 35 | ''; 36 | } 37 | -------------------------------------------------------------------------------- /home/nvim/config/lua/comment-config.lua: -------------------------------------------------------------------------------- 1 | require("Comment").setup({ 2 | ---LHS of toggle mappings in NORMAL mode 3 | toggler = { 4 | ---Line-comment toggle keymap 5 | line = "ctb", 6 | ---Block-comment toggle keymap 7 | block = "ctb", 8 | }, 9 | ---LHS of operator-pending mappings in NORMAL and VISUAL mode 10 | opleader = { 11 | ---Line-comment keymap 12 | line = "cc", 13 | ---Block-comment keymap 14 | block = "cb", 15 | }, 16 | ---LHS of extra mappings 17 | extra = { 18 | ---Add comment on the line above 19 | above = "cO", 20 | ---Add comment on the line below 21 | below = "co", 22 | ---Add comment at the end of line 23 | eol = "cA", 24 | }, 25 | }) 26 | 27 | require("which-key").add({ 28 | { "c", group = "Comment", icon = "󰅺" }, 29 | { "ct", group = "Toggle", icon = "󰔡" }, 30 | }) 31 | -------------------------------------------------------------------------------- /darwin/homebrew/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | { 3 | homebrew = { 4 | enable = config.my-darwin.isWork || config.my-darwin.isServer; 5 | onActivation = { 6 | cleanup = "uninstall"; 7 | }; 8 | taps = lib.optionals config.my-darwin.isWork [ 9 | { 10 | name = "toasttab/toast"; 11 | clone_target = "git@github.toasttab.com:toasttab/homebrew-toast"; 12 | } 13 | { 14 | name = "snyk/tap"; 15 | } 16 | ]; 17 | brews = 18 | lib.optionals config.my-darwin.isWork [ 19 | "libffi" 20 | "cocoapods" 21 | "lunchbox" 22 | "toasttab/toast/braid" 23 | "snyk" 24 | "flaggy" 25 | ] ++ 26 | lib.optionals config.my-darwin.isServer [ 27 | "handbrake" 28 | ]; 29 | casks = lib.optionals config.my-darwin.isServer [ 30 | "filebot" 31 | ]; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /templates/java/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example Java Project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, system, ... }: { 13 | _module.args.pkgs = import inputs.nixpkgs { 14 | inherit system; 15 | overlays = [ 16 | (final: prev: rec { 17 | jdk = prev.jdk11; 18 | gradle = prev.gradle.override { 19 | java = jdk; 20 | }; 21 | maven = prev.maven.override { 22 | jdk_headless = jdk; 23 | }; 24 | }) 25 | ]; 26 | config = { }; 27 | }; 28 | devShells.default = pkgs.mkShell { 29 | packages = with pkgs; [ jdk gradle maven ]; 30 | }; 31 | }; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /templates/kotlin/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example Java Project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, system, ... }: { 13 | _module.args.pkgs = import inputs.nixpkgs { 14 | inherit system; 15 | overlays = [ 16 | (final: prev: rec { 17 | jdk = prev.jdk11; 18 | gradle = prev.gradle.override { 19 | java = jdk; 20 | }; 21 | kotlin = prev.kotlin.override { 22 | jre = jdk; 23 | }; 24 | }) 25 | ]; 26 | config = { }; 27 | }; 28 | devShells.default = pkgs.mkShell { 29 | packages = with pkgs; [ kotlin gradle gcc ncurses patchelf zlib ]; 30 | }; 31 | }; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /pkgs/toast/toast-services/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , lib 3 | , makeWrapper 4 | , awscli2 5 | , jq 6 | }: 7 | stdenv.mkDerivation { 8 | pname = "toast-services"; 9 | version = "1.0"; 10 | 11 | src = fetchGit { 12 | url = "git@github.toasttab.com:toasttab/toast-services.git"; 13 | rev = "ec5365aff322086af75abb1bcf7f18a675249d57"; 14 | ref = "development"; 15 | }; 16 | 17 | nativeBuildInputs = [ 18 | makeWrapper 19 | ]; 20 | 21 | installPhase = '' 22 | mkdir -p $out/bin 23 | mkdir -p $out/bin/lib 24 | cp deploy_g2_service.sh $out/bin/deploy_g2_service.sh 25 | cp destroy_g2_service.sh $out/bin/destroy_g2_service.sh 26 | cp lib/check_aws_env.bash $out/bin/lib/check_aws_env.bash 27 | cp lib/countdown.bash $out/bin/lib/countdown.bash 28 | cp lib/aws_libs.bash $out/bin/lib/aws_libs.bash 29 | ''; 30 | 31 | postFixup = '' 32 | wrapProgram $out/bin/deploy_g2_service.sh \ 33 | --prefix PATH : ${lib.makeBinPath [ awscli2 jq ]} 34 | wrapProgram $out/bin/destroy_g2_service.sh \ 35 | --prefix PATH : ${lib.makeBinPath [ awscli2 jq ]} 36 | ''; 37 | } 38 | -------------------------------------------------------------------------------- /home/nvim/config/lua/settings.lua: -------------------------------------------------------------------------------- 1 | local opt = vim.opt 2 | local g = vim.g 3 | 4 | -- global options -- 5 | opt.incsearch = true -- Find the next match as we type the search 6 | opt.hlsearch = true -- Hilight searches by default 7 | opt.shada = "'100,f1" -- Save up to 100 marks, enable capital marks 8 | opt.ignorecase = true -- Ignore case when searching... 9 | opt.smartcase = true -- ...unless we type a capital 10 | opt.autoindent = true 11 | opt.smartindent = true 12 | opt.tabstop = 4 13 | opt.shiftwidth = 4 14 | opt.expandtab = true 15 | opt.termguicolors = true 16 | opt.cursorline = true 17 | opt.relativenumber = true 18 | opt.number = true 19 | opt.signcolumn = "yes:2" 20 | 21 | vim.o.mousemoveevent = true 22 | 23 | -- Set leader key 24 | g.mapleader = "," 25 | 26 | -- Color Scheme Settings 27 | vim.cmd.colorscheme("catppuccin-frappe") 28 | 29 | vim.diagnostic.config({ 30 | signs = { 31 | text = { 32 | [vim.diagnostic.severity.ERROR] = "", 33 | [vim.diagnostic.severity.WARN] = "", 34 | [vim.diagnostic.severity.INFO] = "\u{f05a}", 35 | [vim.diagnostic.severity.HINT] = "", 36 | }, 37 | }, 38 | virtual_text = false, 39 | }) 40 | -------------------------------------------------------------------------------- /home/nvim/config/lua/nvim-tree-config.lua: -------------------------------------------------------------------------------- 1 | require("nvim-tree").setup({ 2 | disable_netrw = true, 3 | hijack_netrw = true, 4 | 5 | hijack_directories = { 6 | enable = true, 7 | auto_open = true, 8 | }, 9 | 10 | hijack_cursor = false, 11 | update_cwd = false, 12 | diagnostics = { 13 | enable = true, 14 | icons = { 15 | hint = "", 16 | info = "", 17 | warning = "", 18 | error = "", 19 | }, 20 | }, 21 | update_focused_file = { 22 | enable = false, 23 | update_cwd = false, 24 | ignore_list = {}, 25 | }, 26 | system_open = { 27 | cmd = nil, 28 | args = {}, 29 | }, 30 | view = { 31 | width = 25, 32 | side = "left", 33 | }, 34 | actions = { 35 | open_file = { 36 | resize_window = true, 37 | }, 38 | }, 39 | }) 40 | 41 | require("which-key").add({ 42 | { "t", group = "Tree", icon = "󱏒" }, 43 | { "tt", ":NvimTreeToggle", desc = "Tree: Toggle", icon = "󰔡", silent = true }, 44 | { "tr", ":NvimTreeRefresh", desc = "Tree: Refresh", icon = "󰑐", silent = true }, 45 | { "tf", ":NvimTreeFindFile", desc = "Tree: Find file", icon = "󰍉", silent = true }, 46 | }) 47 | -------------------------------------------------------------------------------- /home/nvim/config/lua/bufferline-config.lua: -------------------------------------------------------------------------------- 1 | require("bufferline").setup({ 2 | options = { 3 | always_show_bufferline = false, 4 | show_buffer_close_icons = false, 5 | show_close_icon = false, 6 | diagnostics = "nvim_lsp", 7 | }, 8 | highlights = require("catppuccin.special.bufferline").get_theme(), 9 | }) 10 | 11 | require("which-key").add({ 12 | { 13 | "]b", 14 | "BufferLineCycleNext", 15 | desc = "BufferLine: Next buffer", 16 | icon = "󰒭", 17 | silent = true, 18 | noremap = true, 19 | }, 20 | { 21 | "[b", 22 | "BufferLineCyclePrev", 23 | desc = "BufferLine: Previous buffer", 24 | icon = "󰒮", 25 | silent = true, 26 | noremap = true, 27 | }, 28 | { "bl", group = "BufferLine", icon = "󰕘" }, 29 | { 30 | "ble", 31 | "BufferLineSortByExtension", 32 | desc = "BufferLine: Organize by extension", 33 | icon = "󰒺", 34 | silent = true, 35 | noremap = true, 36 | }, 37 | { 38 | "bld", 39 | "BufferLineSortByDirectory", 40 | desc = "BufferLine: Organize by directory", 41 | icon = "󰝰", 42 | silent = true, 43 | noremap = true, 44 | }, 45 | }) 46 | -------------------------------------------------------------------------------- /hosts/cicucci-builder/disko-config.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "/dev/nvme0n1"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | ESP = { 11 | size = "512MiB"; 12 | type = "EF00"; 13 | priority = 3; 14 | content = { 15 | type = "filesystem"; 16 | format = "vfat"; 17 | mountpoint = "/boot"; 18 | mountOptions = [ "umask=0077" ]; 19 | }; 20 | }; 21 | nixos = { 22 | end = "-8GiB"; 23 | priority = 1; 24 | content = { 25 | type = "filesystem"; 26 | format = "ext4"; 27 | mountpoint = "/"; 28 | }; 29 | }; 30 | swap = { 31 | size = "100%"; 32 | priority = 2; 33 | content = { 34 | type = "swap"; 35 | }; 36 | }; 37 | }; 38 | }; 39 | }; 40 | }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /hosts/cicucci-homelab/disko-config.nix: -------------------------------------------------------------------------------- 1 | _: { 2 | disko.devices = { 3 | disk = { 4 | main = { 5 | type = "disk"; 6 | device = "/dev/nvme0n1"; 7 | content = { 8 | type = "gpt"; 9 | partitions = { 10 | ESP = { 11 | size = "512MiB"; 12 | type = "EF00"; 13 | priority = 1; 14 | content = { 15 | type = "filesystem"; 16 | format = "vfat"; 17 | mountpoint = "/boot"; 18 | mountOptions = [ "umask=0077" ]; 19 | }; 20 | }; 21 | nixos = { 22 | end = "-18GiB"; 23 | priority = 2; 24 | content = { 25 | type = "filesystem"; 26 | format = "ext4"; 27 | mountpoint = "/"; 28 | }; 29 | }; 30 | swap = { 31 | size = "100%"; 32 | priority = 3; 33 | content = { 34 | type = "swap"; 35 | }; 36 | }; 37 | }; 38 | }; 39 | }; 40 | }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /home/delta/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | programs.delta = { 3 | enable = true; 4 | enableGitIntegration = true; 5 | options = { 6 | commit-decoration-style = "bold box ul"; 7 | dark = true; 8 | file-decoration-style = "none"; 9 | file-style = "omit"; 10 | hunk-header-decoration-style = "\"#88C0D0\" box ul"; 11 | hunk-header-file-style = "white"; 12 | hunk-header-line-number-style = "bold \"#5E81AC\""; 13 | hunk-header-style = "file line-number syntax"; 14 | line-numbers = true; 15 | line-numbers-left-style = "\"#88C0D0\""; 16 | line-numbers-minus-style = "\"#BF616A\""; 17 | line-numbers-plus-style = "\"#A3BE8C\""; 18 | line-numbers-right-style = "\"#88C0D0\""; 19 | line-numbers-zero-style = "white"; 20 | minus-emph-style = "syntax bold \"#780000\""; 21 | minus-style = "syntax \"#400000\""; 22 | navigate = true; 23 | plus-emph-style = "syntax bold \"#007800\""; 24 | plus-style = "syntax \"#004000\""; 25 | whitespace-error-style = "\"#280050\" reverse"; 26 | zero-style = "syntax"; 27 | syntax-theme = "catppuccin-frappe"; 28 | }; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /home/claude-code/config/commands/tasks/create_plan.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Create a plan 3 | --- 4 | 5 | Draft a detailed, step-by-step blueprint for building this project. Then, once you have a solid plan, break it down into small, iterative chunks that build on each other. Look at these chunks and then go another round to break it into small steps. review the results and make sure that the steps are small enough to be implemented safely, but big enough to move the project forward. Iterate until you feel that the steps are right sized for this project. 6 | 7 | From here you should have the foundation to provide a series of prompts for a code-generation LLM that will implement each step. Prioritize best practices, and incremental progress, ensuring no big jumps in complexity at any stage. Make sure that each prompt builds on the previous prompts, and ends with wiring things together. There should be no hanging or orphaned code that isn't integrated into a previous step. 8 | 9 | Make sure and separate each prompt section. Use markdown. Each prompt should be tagged as text using code tags. The goal is to output prompts, but context, etc is important as well. 10 | 11 | #$ARGUMENTS 12 | 13 | -------------------------------------------------------------------------------- /home/ghostty/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.ghostty = { 4 | enable = true; 5 | enableZshIntegration = true; 6 | package = if pkgs.stdenv.isLinux then pkgs.ghostty else null; 7 | settings = { 8 | theme = "catppuccin-frappe"; 9 | font-family = "Terminess Nerd Font Mono"; 10 | font-size = 14; 11 | }; 12 | themes = { 13 | catppuccin-frappe = { 14 | palette = [ 15 | "0=#51576d" 16 | "1=#e78284" 17 | "2=#a6d189" 18 | "3=#e5c890" 19 | "4=#8caaee" 20 | "5=#f4b8e4" 21 | "6=#81c8be" 22 | "7=#a5adce" 23 | "8=#626880" 24 | "9=#e78284" 25 | "10=#a6d189" 26 | "11=#e5c890" 27 | "12=#8caaee" 28 | "13=#f4b8e4" 29 | "14=#81c8be" 30 | "15=#b5bfe2" 31 | ]; 32 | background = "303446"; 33 | foreground = "c6d0f5"; 34 | cursor-color = "f2d5cf"; 35 | cursor-text = "232634"; 36 | selection-background = "44495d"; 37 | selection-foreground = "c6d0f5"; 38 | split-divider-color = "414559"; 39 | }; 40 | }; 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /linux/adguardhome/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | with lib; 3 | { 4 | config = mkIf config.my-linux.adblocker.enable { 5 | services.adguardhome = { 6 | inherit (config.my-linux.adblocker) enable; 7 | settings = { 8 | bind_host = "0.0.0.0"; 9 | bind_port = 80; 10 | http = { 11 | address = "0.0.0.0:80"; 12 | }; 13 | dns = { 14 | bind_host = "0.0.0.0"; 15 | bind_hosts = [ "0.0.0.0" ]; 16 | bootstrap_dns = 17 | if config.my-linux.adblocker.useUnbound then [ 18 | "127.0.0.1:5335" 19 | ] else [ 20 | "1.1.1.1" 21 | "1.0.0.1" 22 | ]; 23 | upstream_dns = 24 | if config.my-linux.adblocker.useUnbound then [ 25 | "127.0.0.1:5335" 26 | ] else [ 27 | "1.1.1.1" 28 | "1.0.0.1" 29 | ]; 30 | enable_dnssec = true; 31 | ratelimit = 0; 32 | }; 33 | }; 34 | }; 35 | 36 | networking = { 37 | firewall = { 38 | allowedTCPPorts = [ 53 80 ]; 39 | allowedUDPPorts = [ 53 ]; 40 | }; 41 | }; 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /home/claude-code/config/commands/tasks/create_plan_with_tdd.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Create a plan with TDD 3 | --- 4 | 5 | Draft a detailed, step-by-step blueprint for building this project. Then, once you have a solid plan, break it down into small, iterative chunks that build on each other. Look at these chunks and then go another round to break it into small steps. Review the results and make sure that the steps are small enough to be implemented safely with strong testing, but big enough to move the project forward. Iterate until you feel that the steps are right sized for this project. 6 | 7 | From here you should have the foundation to provide a series of prompts for a code-generation LLM that will implement each step in a test-driven manner. Prioritize best practices, incremental progress, and early testing, ensuring no big jumps in complexity at any stage. Make sure that each prompt builds on the previous prompts, and ends with wiring things together. There should be no hanging or orphaned code that isn't integrated into a previous step. 8 | 9 | Make sure and separate each prompt section. Use markdown. Each prompt should be tagged as text using code tags. The goal is to output prompts, but context, etc is important as well. 10 | 11 | #$ARGUMENTS 12 | 13 | -------------------------------------------------------------------------------- /pkgs/homebridge/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , buildNpmPackage 3 | , fetchFromGitHub 4 | , jq 5 | , 6 | }: 7 | 8 | buildNpmPackage (finalAttrs: { 9 | pname = "homebridge"; 10 | version = "1.11.1"; 11 | 12 | src = fetchFromGitHub { 13 | owner = "homebridge"; 14 | repo = "homebridge"; 15 | tag = "v${finalAttrs.version}"; 16 | hash = "sha256-E21HowCRD78MZW3+um6vN5/NLncF/bt9v/Tw+RYe5xM="; 17 | }; 18 | 19 | npmDepsHash = "sha256-Da64zHwvX0W1viNhy4afr60onlWqbizaVox9Un6c65Y="; 20 | 21 | # Homebridge's clean phase attempts to install rimraf directly, which fails in nix builds 22 | # rimraf is already in the declared dependencies, so we just don't need to do it. 23 | # This will replace "npm install rimraf && rimraf lib/" with "rimraf lib/". 24 | preBuild = '' 25 | cat package.json | ${jq}/bin/jq '.scripts.clean = "rimraf lib/"' > package.json.tmp 26 | mv package.json.tmp package.json 27 | ''; 28 | 29 | meta = { 30 | description = "Lightweight emulator of iOS HomeKit API"; 31 | homepage = "https://github.com/homebridge/homebridge"; 32 | license = lib.licenses.asl20; 33 | mainProgram = "homebridge"; 34 | platforms = lib.platforms.linux ++ lib.platforms.darwin; 35 | maintainers = with lib.maintainers; [ fmoda3 ]; 36 | }; 37 | }) 38 | -------------------------------------------------------------------------------- /pkgs/ccusage/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , buildNpmPackage 3 | , fetchzip 4 | , nodejs_20 5 | }: 6 | 7 | buildNpmPackage rec { 8 | pname = "ccusage"; 9 | version = "17.2.0"; 10 | 11 | nodejs = nodejs_20; 12 | 13 | src = fetchzip { 14 | url = "https://registry.npmjs.org/ccusage/-/ccusage-${version}.tgz"; 15 | hash = "sha256-HD9zSUNpA7W4E/A+JHF0X4C8V2MBLZEzqQhO25uRsTU="; 16 | }; 17 | 18 | npmDepsHash = "sha256-tjCEh9n6OzyvY/ENC/EsnFFxnPGJDnYstJ1R1S/MrFA="; 19 | forceEmptyCache = true; 20 | 21 | postPatch = '' 22 | cp ${./package-lock.json} package-lock.json 23 | ''; 24 | 25 | dontNpmBuild = true; 26 | 27 | installPhase = '' 28 | runHook preInstall 29 | 30 | mkdir -p $out/bin $out/lib/node_modules/ccusage 31 | cp -r . $out/lib/node_modules/ccusage/ 32 | 33 | # Create symlink for the binary 34 | ln -s $out/lib/node_modules/ccusage/dist/index.js $out/bin/ccusage 35 | chmod +x $out/bin/ccusage 36 | 37 | runHook postInstall 38 | ''; 39 | 40 | meta = { 41 | description = "Analyze your Claude Code token usage and costs from local JSONL files"; 42 | homepage = "https://github.com/ryoppippi/ccusage"; 43 | license = lib.licenses.mit; 44 | mainProgram = "ccusage"; 45 | maintainers = [ ]; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /home/nvim/config/lua/claude-code-config.lua: -------------------------------------------------------------------------------- 1 | require("claudecode").setup({}) 2 | 3 | require("which-key").add({ 4 | { "a", group = "AI", icon = "󱜙" }, 5 | { "ac", "ClaudeCode", desc = "Toggle Claude", icon = "󱜙" }, 6 | { "af", "ClaudeCodeFocus", desc = "Focus Claude", icon = "󱜙" }, 7 | { "ar", "ClaudeCode --resume", desc = "Resume Claude", icon = "󱜙" }, 8 | { "aC", "ClaudeCode --continue", desc = "Continue Claude", icon = "󱜙" }, 9 | { "ab", "ClaudeCodeAdd %", desc = "Add current buffer", icon = "󱜙" }, 10 | { "as", "ClaudeCodeSend", mode = "v", desc = "Send to Claude", icon = "󱜙" }, 11 | -- Diff management 12 | { "aa", "ClaudeCodeDiffAccept", desc = "Accept diff", icon = "󱜙" }, 13 | { "ad", "ClaudeCodeDiffDeny", desc = "Deny diff", icon = "󱜙" }, 14 | }) 15 | 16 | vim.api.nvim_create_autocmd("FileType", { 17 | pattern = { "NvimTree", "neo-tree", "oil" }, 18 | callback = function() 19 | require("which-key").register({ 20 | { 21 | "as", 22 | "ClaudeCodeTreeAdd", 23 | desc = "Add file", 24 | ft = { "NvimTree", "neo-tree", "oil" }, 25 | icon = "󱜙", 26 | }, 27 | }, { buffer = 0 }) 28 | end, 29 | }) 30 | -------------------------------------------------------------------------------- /home/nvim/config/lua/flash-config.lua: -------------------------------------------------------------------------------- 1 | require("flash").setup({ 2 | modes = { 3 | char = { 4 | enabled = true, 5 | jump_labels = true, 6 | }, 7 | }, 8 | }) 9 | 10 | require("which-key").add({ 11 | { 12 | "s", 13 | function() 14 | require("flash").jump() 15 | end, 16 | desc = "Flash: Jump", 17 | icon = "", 18 | mode = { "n", "x", "o" }, 19 | noremap = true, 20 | silent = true, 21 | }, 22 | { 23 | "S", 24 | function() 25 | require("flash").treesitter() 26 | end, 27 | desc = "Flash: Treesitter", 28 | icon = "", 29 | mode = { "n", "x", "o" }, 30 | noremap = true, 31 | silent = true, 32 | }, 33 | { 34 | "r", 35 | function() 36 | require("flash").remote() 37 | end, 38 | desc = "Flash: Remote", 39 | icon = "", 40 | mode = "o", 41 | noremap = true, 42 | silent = true, 43 | }, 44 | { 45 | "R", 46 | function() 47 | require("flash").treesitter_search() 48 | end, 49 | desc = "Flash: Treesitter Search", 50 | icon = "", 51 | mode = { "o", "x" }, 52 | noremap = true, 53 | silent = true, 54 | }, 55 | { 56 | "", 57 | function() 58 | require("flash").toggle() 59 | end, 60 | desc = "Toggle Flash Search", 61 | icon = "", 62 | mode = { "c" }, 63 | noremap = true, 64 | silent = true, 65 | }, 66 | }) 67 | -------------------------------------------------------------------------------- /hosts/cicucci-homelab/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { config, lib, modulesPath, ... }: 5 | 6 | { 7 | imports = [ 8 | (modulesPath + "/installer/scan/not-detected.nix") 9 | ./disko-config.nix 10 | ]; 11 | 12 | boot = { 13 | initrd = { 14 | availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "usb_storage" "sd_mod" ]; 15 | kernelModules = [ ]; 16 | }; 17 | kernelModules = [ "kvm-intel" ]; 18 | extraModulePackages = [ ]; 19 | }; 20 | 21 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 22 | # (the default) this is the recommended approach. When using systemd-networkd it's 23 | # still possible to use this option, but it's recommended to use it in conjunction 24 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 25 | networking.useDHCP = lib.mkDefault true; 26 | # networking.interfaces.eno1.useDHCP = lib.mkDefault true; 27 | 28 | nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; 29 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /home/nvim/config/lua/trouble-config.lua: -------------------------------------------------------------------------------- 1 | require("trouble").setup({}) 2 | 3 | require("which-key").add({ 4 | { "x", group = "Trouble/Diagnostics", icon = "󱖫" }, 5 | { 6 | "xx", 7 | "Trouble diagnostics toggle", 8 | desc = "Trouble: Diagnostics", 9 | icon = "󱖫", 10 | silent = true, 11 | noremap = true, 12 | }, 13 | { 14 | "xX", 15 | "Trouble diagnostics toggle filter.buf=0", 16 | desc = "Trouble: Buffer Diagnostics", 17 | icon = "󱖫", 18 | silent = true, 19 | noremap = true, 20 | }, 21 | { 22 | "xs", 23 | "Trouble symbols toggle focus=false", 24 | desc = "Trouble: Symbols", 25 | icon = "󱖫", 26 | silent = true, 27 | noremap = true, 28 | }, 29 | { 30 | "xl", 31 | "Trouble lsp toggle focus=false win.position=right", 32 | desc = "Trouble: LSP Definitions / references / ...", 33 | icon = "󱖫", 34 | silent = true, 35 | noremap = true, 36 | }, 37 | { 38 | "xL", 39 | "Trouble loclist toggle", 40 | desc = "Trouble: Location List", 41 | icon = "󱖫", 42 | silent = true, 43 | noremap = true, 44 | }, 45 | { 46 | "xQ", 47 | "Trouble qflist toggle", 48 | desc = "Trouble: Quickfix List", 49 | icon = "󱖫", 50 | silent = true, 51 | noremap = true, 52 | }, 53 | }) 54 | -------------------------------------------------------------------------------- /hosts/cicucci-dns/hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # Do not modify this file! It was generated by ‘nixos-generate-config’ 2 | # and may be overwritten by future invocations. Please make changes 3 | # to /etc/nixos/configuration.nix instead. 4 | { lib, modulesPath, ... }: 5 | 6 | { 7 | imports = 8 | [ 9 | (modulesPath + "/installer/scan/not-detected.nix") 10 | ]; 11 | 12 | boot = { 13 | initrd = { 14 | availableKernelModules = [ "usbhid" ]; 15 | kernelModules = [ ]; 16 | }; 17 | kernelModules = [ ]; 18 | extraModulePackages = [ ]; 19 | }; 20 | 21 | fileSystems."/" = 22 | { 23 | device = "/dev/disk/by-label/NIXOS_SD"; 24 | fsType = "ext4"; 25 | }; 26 | 27 | swapDevices = [{ device = "/swapfile"; size = 2048; }]; 28 | 29 | # Enables DHCP on each ethernet and wireless interface. In case of scripted networking 30 | # (the default) this is the recommended approach. When using systemd-networkd it's 31 | # still possible to use this option, but it's recommended to use it in conjunction 32 | # with explicit per-interface declarations with `networking.interfaces..useDHCP`. 33 | networking.useDHCP = lib.mkDefault true; 34 | # networking.interfaces.eth0.useDHCP = lib.mkDefault true; 35 | # networking.interfaces.wlan0.useDHCP = lib.mkDefault true; 36 | 37 | powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; 38 | } 39 | -------------------------------------------------------------------------------- /pkgs/default.nix: -------------------------------------------------------------------------------- 1 | final: prev: 2 | { 3 | # Adding packages here, makes them accessible from "pkgs" 4 | catppuccin = { 5 | bat = prev.callPackage ./catppuccin/bat { }; 6 | btop = prev.callPackage ./catppuccin/btop { }; 7 | yazi = prev.callPackage ./catppuccin/yazi { }; 8 | zsh-syntax-highlighting = prev.callPackage ./catppuccin/zsh-syntax-highlighting { }; 9 | }; 10 | ccusage = prev.callPackage ./ccusage { }; 11 | claude-code = prev.callPackage ./claude-code { }; 12 | codex = prev.callPackage ./codex { }; 13 | homebridge = prev.callPackage ./homebridge { }; 14 | homebridge-config-ui-x = prev.callPackage ./homebridge-config-ui-x { }; 15 | kotlin-lsp = prev.callPackage ./kotlin-lsp { }; 16 | mcp = { 17 | github = prev.callPackage ./mcp/github { }; 18 | }; 19 | nix-cleanup = prev.callPackage ./nix-cleanup { }; 20 | # python3Packages = prev.python3Packages // { 21 | # toast-tools = prev.callPackage ./toast-tools { }; 22 | # }; 23 | toast = { 24 | oktoast = prev.callPackage ./toast/oktoast { }; 25 | toast-services = prev.callPackage ./toast/toast-services { }; 26 | toastApiKeyHelper = prev.callPackage ./toast/toastApiKeyHelper { }; 27 | }; 28 | vimPlugins = prev.vimPlugins // { 29 | claudecode-nvim = prev.callPackage ./vimPlugins/claudecode-nvim { }; 30 | tiny-code-action-nvim = prev.callPackage ./vimPlugins/tiny-code-action-nvim { }; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /installer/system-installer.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | with lib; 3 | let 4 | cfg = config.installer; 5 | 6 | inherit (cfg.targetSystem.config.system) build; 7 | 8 | # disko 9 | disko = pkgs.writeShellScriptBin "disko" ''${build.diskoScript}''; 10 | disko-mount = pkgs.writeShellScriptBin "disko-mount" "${build.mountScript}"; 11 | disko-format = pkgs.writeShellScriptBin "disko-format" "${build.formatScript}"; 12 | 13 | system = build.toplevel; 14 | 15 | # installer script 16 | install-system = pkgs.writeShellScriptBin "install-system" '' 17 | set -euo pipefail 18 | 19 | echo "Formatting disks..." 20 | . ${disko-format}/bin/disko-format 21 | 22 | echo "Mounting disks..." 23 | . ${disko-mount}/bin/disko-mount 24 | 25 | echo "Installing system..." 26 | nixos-install --system ${system} 27 | 28 | echo "Done!" 29 | ''; 30 | in 31 | { 32 | options.installer = { 33 | targetSystem = mkOption { 34 | type = types.attrs; 35 | default = null; 36 | description = '' 37 | A reference to a built nixosSystem 38 | ''; 39 | }; 40 | }; 41 | 42 | config = { 43 | # we don't want to generate filesystem entries on this image 44 | disko.enableConfig = lib.mkDefault false; 45 | 46 | # add disko commands to format and mount disks 47 | environment.systemPackages = [ 48 | disko 49 | disko-mount 50 | disko-format 51 | install-system 52 | ]; 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /home/nvim/config/lua/hover-config.lua: -------------------------------------------------------------------------------- 1 | require("hover").setup({ 2 | init = function() 3 | -- Require providers 4 | require("hover.providers.lsp") 5 | require("hover.providers.dap") 6 | require("hover.providers.fold_preview") 7 | require("hover.providers.diagnostic") 8 | require("hover.providers.man") 9 | require("hover.providers.dictionary") 10 | end, 11 | preview_opts = { 12 | border = "rounded", 13 | }, 14 | -- Whether the contents of a currently open hover window should be moved 15 | -- to a :h preview-window when pressing the hover keymap. 16 | preview_window = false, 17 | title = true, 18 | mouse_providers = { 19 | "LSP", 20 | }, 21 | mouse_delay = 1000, 22 | }) 23 | 24 | -- Setup keymaps 25 | require("which-key").add({ 26 | { 27 | "K", 28 | require("hover").hover, 29 | desc = "Hover", 30 | noremap = true, 31 | silent = true, 32 | }, 33 | { 34 | "gK", 35 | require("hover").hover_select, 36 | desc = "Hover select source", 37 | noremap = true, 38 | silent = true, 39 | }, 40 | { 41 | "", 42 | function() 43 | require("hover").hover_switch("previous") 44 | end, 45 | desc = "Hover previous source", 46 | noremap = true, 47 | silent = true, 48 | }, 49 | { 50 | "", 51 | function() 52 | require("hover").hover_switch("next") 53 | end, 54 | desc = "Hover next source", 55 | noremap = true, 56 | silent = true, 57 | }, 58 | }) 59 | 60 | -- Mouse support 61 | vim.keymap.set("n", "", require("hover").hover_mouse, { desc = "hover.nvim (mouse)" }) 62 | -------------------------------------------------------------------------------- /home/nvim/config/lua/treesitter-config.lua: -------------------------------------------------------------------------------- 1 | require("nvim-treesitter.configs").setup({ 2 | highlight = { 3 | enable = true, 4 | }, 5 | textobjects = { 6 | select = { 7 | enable = true, 8 | lookahead = true, 9 | keymaps = { 10 | ["af"] = "@function.outer", 11 | ["if"] = "@function.inner", 12 | ["ac"] = "@class.outer", 13 | ["ic"] = "@class.inner", 14 | ["aa"] = "@parameter.outer", 15 | ["ia"] = "@parameter.inner", 16 | ["ab"] = "@block.outer", 17 | ["ib"] = "@block.inner", 18 | ["al"] = "@loop.outer", 19 | ["il"] = "@loop.inner", 20 | ["ai"] = "@conditional.outer", 21 | ["ii"] = "@conditional.inner", 22 | }, 23 | }, 24 | move = { 25 | enable = true, 26 | set_jumps = true, 27 | goto_next_start = { 28 | ["]f"] = "@function.outer", 29 | ["]c"] = "@class.outer", 30 | ["]a"] = "@parameter.inner", 31 | }, 32 | goto_next_end = { 33 | ["]F"] = "@function.outer", 34 | ["]C"] = "@class.outer", 35 | ["]A"] = "@parameter.inner", 36 | }, 37 | goto_previous_start = { 38 | ["[f"] = "@function.outer", 39 | ["[c"] = "@class.outer", 40 | ["[a"] = "@parameter.inner", 41 | }, 42 | goto_previous_end = { 43 | ["[F"] = "@function.outer", 44 | ["[C"] = "@class.outer", 45 | ["[A"] = "@parameter.inner", 46 | }, 47 | }, 48 | swap = { 49 | enable = true, 50 | swap_next = { 51 | ["sn"] = "@parameter.inner", 52 | }, 53 | swap_previous = { 54 | ["sp"] = "@parameter.inner", 55 | }, 56 | }, 57 | }, 58 | }) 59 | -------------------------------------------------------------------------------- /linux/unbound/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | with lib; 3 | { 4 | config = mkIf config.my-linux.adblocker.useUnbound { 5 | services.unbound = { 6 | enable = true; 7 | settings = { 8 | server = { 9 | verbosity = 0; 10 | 11 | interface = [ "127.0.0.1" ]; 12 | port = 5335; 13 | 14 | do-ip4 = "yes"; 15 | do-udp = "yes"; 16 | do-tcp = "yes"; 17 | do-ip6 = "no"; 18 | prefer-ip6 = "no"; 19 | 20 | harden-glue = "yes"; 21 | harden-dnssec-stripped = "yes"; 22 | 23 | use-caps-for-id = "no"; 24 | 25 | edns-buffer-size = 1232; 26 | 27 | prefetch = "yes"; 28 | 29 | num-threads = 4; 30 | so-reuseport = "yes"; 31 | so-rcvbuf = "4m"; 32 | so-sndbuf = "4m"; 33 | msg-cache-slabs = 4; 34 | rrset-cache-slabs = 4; 35 | infra-cache-slabs = 4; 36 | key-cache-slabs = 4; 37 | 38 | rrset-cache-size = "100m"; 39 | msg-cache-size = "50m"; 40 | 41 | outgoing-range = 8192; 42 | num-queries-per-thread = 4096; 43 | 44 | private-address = [ 45 | "192.168.0.0/16" 46 | "169.254.0.0/16" 47 | "172.16.0.0/12" 48 | "10.0.0.0/8" 49 | "fd00::/8" 50 | "fe80::/10" 51 | ]; 52 | }; 53 | }; 54 | }; 55 | 56 | boot.kernel.sysctl = { 57 | "net.core.rmem_max" = 26214400; 58 | "net.core.wmem_max" = 26214400; 59 | }; 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /templates/python/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Example Python Project"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | flake-parts.url = "github:hercules-ci/flake-parts"; 7 | }; 8 | 9 | outputs = inputs@{ self, flake-parts, ... }: 10 | flake-parts.lib.mkFlake { inherit inputs; } { 11 | systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 12 | perSystem = { pkgs, ... }: 13 | let 14 | python = pkgs.python3; 15 | in 16 | { 17 | devShells.default = pkgs.mkShell { 18 | venvDir = ".venv"; 19 | 20 | postShellHook = '' 21 | venvVersionWarn() { 22 | local venvVersion 23 | venvVersion="$("$venvDir/bin/python" -c 'import platform; print(platform.python_version())')" 24 | 25 | [[ "$venvVersion" == "${python.version}" ]] && return 26 | 27 | cat <?", 6 | function() 7 | require("which-key").show({ global = false }) 8 | end, 9 | desc = "Buffer Local Keymaps (which-key)", 10 | icon = "󰘳", 11 | }, 12 | { "", ":Telescope keymaps", desc = "Open keymaps", icon = "󰌌", noremap = true }, 13 | -- Movement keybinds 14 | { "", "h", desc = "Panes: Move left", icon = "󰁍", noremap = true }, 15 | { "", "j", desc = "Panes: Move down", icon = "󰁅", noremap = true }, 16 | { "", "k", desc = "Panes: Move up", icon = "󰁝", noremap = true }, 17 | { "", "l", desc = "Panes: Move right", icon = "󰁔", noremap = true }, 18 | -- High level groups 19 | { "]", group = "Next", icon = "󰒭" }, 20 | { "[", group = "Previous", icon = "󰒮" }, 21 | { "j", group = "Jump", icon = "󰉁" }, 22 | { "s", group = "Swap", icon = "󰓡" }, 23 | -- Buffers 24 | { "b", group = "Buffers", icon = "󰓩" }, 25 | { "bd", ":bdelete", desc = "Delete buffer", icon = "󰆴" }, 26 | { "bn", ":bnext", desc = "Next buffer", icon = "󰒭" }, 27 | { "bp", ":bprev", desc = "Previous buffer", icon = "󰒮" }, 28 | -- Window management 29 | { "w", group = "Windows", icon = "󰖲" }, 30 | { "wv", "v", desc = "Split vertical", icon = "󰤼" }, 31 | { "wh", "s", desc = "Split horizontal", icon = "󰤻" }, 32 | { "wc", "c", desc = "Close window", icon = "󰅖" }, 33 | { "wo", "o", desc = "Close other windows", icon = "󰆴" }, 34 | -- Quit 35 | { "q", group = "Quit", icon = "󰿅" }, 36 | { "qq", ":q", desc = "Quit", icon = "󰿅" }, 37 | { "qQ", ":q!", desc = "Force quit", icon = "󰗼" }, 38 | { "qs", ":wq", desc = "Save and Quit", icon = "󰆓" }, 39 | }, 40 | }) 41 | -------------------------------------------------------------------------------- /home/nvim/config/lua/catppuccin-config.lua: -------------------------------------------------------------------------------- 1 | require("catppuccin").setup({ 2 | flavour = "frappe", -- latte, frappe, macchiato, mocha 3 | integrations = { 4 | alpha = true, 5 | blink_cmp = true, 6 | dap = true, 7 | dap_ui = true, 8 | dropbar = true, 9 | fidget = true, 10 | gitsigns = true, 11 | illuminate = { 12 | enabled = true, 13 | lsp = true, 14 | }, 15 | indent_blankline = { 16 | enabled = true, 17 | colored_indent_levels = true, 18 | }, 19 | flash = true, 20 | lsp_trouble = true, 21 | native_lsp = { 22 | enabled = true, 23 | virtual_text = { 24 | errors = { "italic" }, 25 | hints = { "italic" }, 26 | warnings = { "italic" }, 27 | information = { "italic" }, 28 | ok = { "italic" }, 29 | }, 30 | underlines = { 31 | errors = { "underline" }, 32 | hints = { "underline" }, 33 | warnings = { "underline" }, 34 | information = { "underline" }, 35 | ok = { "underline" }, 36 | }, 37 | inlay_hints = { 38 | background = true, 39 | }, 40 | }, 41 | notify = true, 42 | nvimtree = true, 43 | nvim_surround = true, 44 | rainbow_delimiters = true, 45 | semantic_tokens = true, 46 | telescope = { 47 | enabled = true, 48 | }, 49 | treesitter = true, 50 | treesitter_context = true, 51 | which_key = true, 52 | }, 53 | }) 54 | 55 | local colors = { 56 | rosewater = "#f2d5cf", 57 | flamingo = "#eebebe", 58 | pink = "#f4b8e4", 59 | mauve = "#ca9ee6", 60 | red = "#e78284", 61 | maroon = "#ea999c", 62 | peach = "#ef9f76", 63 | yellow = "#e5c890", 64 | green = "#a6d189", 65 | teal = "#81c8be", 66 | sky = "#99d1db", 67 | sapphire = "#85c1dc", 68 | blue = "#8caaee", 69 | lavender = "#babbf1", 70 | text = "#c6d0f5", 71 | subtext1 = "#b5bfe2", 72 | subtext0 = "#a5adce", 73 | overlay2 = "#949cbb", 74 | overlay1 = "#838ba7", 75 | overlay0 = "#737994", 76 | surface2 = "#626880", 77 | surface1 = "#51576d", 78 | surface0 = "#414559", 79 | base = "#303446", 80 | mantle = "#292c3c", 81 | crust = "#232634", 82 | } 83 | -------------------------------------------------------------------------------- /pkgs/toast/toastApiKeyHelper/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , fetchurl 3 | }: 4 | 5 | let 6 | # Define binary information for each platform 7 | version = "dev"; 8 | sources = { 9 | "aarch64-darwin" = { 10 | url = "https://artifactory.eng.toasttab.com/artifactory/go-binaries/toastApiKeyHelper/${version}/toastApiKeyHelper-darwin-arm64"; 11 | sha256 = "sha256-TWX56ljL66eEGpXmHIwezOWPFKXaCGh9dxGc4Ku04vU="; 12 | }; 13 | "x86_64-darwin" = { 14 | url = "https://artifactory.eng.toasttab.com/artifactory/go-binaries/toastApiKeyHelper/${version}/toastApiKeyHelper-darwin-amd64"; 15 | sha256 = "sha256-z/JcteQkWW/descmm6EyKUurG7QmzZlsnWgmGHZ7PM8="; 16 | }; 17 | "x86_64-linux" = { 18 | url = "https://artifactory.eng.toasttab.com/artifactory/go-binaries/toastApiKeyHelper/${version}/toastApiKeyHelper-linux-amd64"; 19 | sha256 = "sha256-zI6GK/Rf3jqroh1czq0/nl8Ka2YEdGuK6QXstSGeg08="; 20 | }; 21 | "aarch64-linux" = { 22 | url = "https://artifactory.eng.toasttab.com/artifactory/go-binaries/toastApiKeyHelper/${version}/toastApiKeyHelper-linux-arm64"; 23 | sha256 = "sha256-Xei5iOvVLqHBnyz3ZC12oZFhbQPNPmJMVWG1qA+PVBI="; 24 | }; 25 | }; 26 | 27 | # Select the appropriate source for the current system 28 | selectedSource = sources.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); 29 | in 30 | stdenv.mkDerivation { 31 | pname = "toastApiKeyHelper"; 32 | inherit version; 33 | 34 | src = fetchurl { 35 | inherit (selectedSource) url sha256; 36 | }; 37 | 38 | dontUnpack = true; 39 | 40 | installPhase = '' 41 | runHook preInstall 42 | 43 | mkdir -p $out/bin 44 | cp $src $out/bin/toastApiKeyHelper 45 | chmod +x $out/bin/toastApiKeyHelper 46 | 47 | runHook postInstall 48 | ''; 49 | 50 | meta = { 51 | description = "Toast API Key Helper utility"; 52 | platforms = [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" "aarch64-linux" ]; 53 | mainProgram = "toastApiKeyHelper"; 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /pkgs/homebridge-config-ui-x/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , buildNpmPackage 4 | , fetchFromGitHub 5 | , fetchNpmDeps 6 | , npmHooks 7 | , python3 8 | , cacert 9 | , 10 | }: 11 | 12 | buildNpmPackage (finalAttrs: { 13 | pname = "homebridge-config-ui-x"; 14 | version = "5.12.0"; 15 | 16 | src = fetchFromGitHub { 17 | owner = "homebridge"; 18 | repo = "homebridge-config-ui-x"; 19 | tag = "v${finalAttrs.version}"; 20 | hash = "sha256-XIhAIDqwhjLzt8+IL5WPbajEecJY0JQQ8yw/dEdYbsw="; 21 | }; 22 | 23 | # Deps hash for the root package 24 | npmDepsHash = "sha256-4BdwMtIDcckeamsklZQOrn2M2z7cZgO66cKsO8TRKb0="; 25 | 26 | # Deps src and hash for ui subdirectory 27 | npmDeps_ui = fetchNpmDeps { 28 | name = "npm-deps-ui"; 29 | src = "${finalAttrs.src}/ui"; 30 | hash = "sha256-05lMX5I0zbVr17bzRjzx2s9NJDbIO1apYUnRPklicNk="; 31 | }; 32 | 33 | # npmFlags = [ "--legacy-peer-deps" ]; 34 | 35 | # Need to also run npm ci in the ui subdirectory 36 | preBuild = '' 37 | # Tricky way to run npmConfigHook multiple times 38 | ( 39 | source ${npmHooks.npmConfigHook}/nix-support/setup-hook 40 | npmRoot=ui npmDeps=${finalAttrs.npmDeps_ui} makeCacheWritable= npmConfigHook 41 | ) 42 | # Required to prevent "ng build" from failing due to 43 | # prompting user for autocompletion 44 | export CI=true 45 | ''; 46 | 47 | # On darwin, the build failed because openpty() is not declared 48 | # Uses the prebuild version of @homebridge/node-pty-prebuilt-multiarch instead 49 | makeCacheWritable = stdenv.hostPlatform.isDarwin; 50 | 51 | nativeBuildInputs = [ 52 | python3 53 | ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ cacert ]; 54 | 55 | meta = { 56 | description = "Configure Homebridge, monitor and backup from a browser"; 57 | homepage = "https://github.com/homebridge/homebridge-config-ui-x"; 58 | license = lib.licenses.mit; 59 | mainProgram = "homebridge-config-ui-x"; 60 | platforms = lib.platforms.linux ++ lib.platforms.darwin; 61 | maintainers = with lib.maintainers; [ fmoda3 ]; 62 | }; 63 | }) 64 | -------------------------------------------------------------------------------- /home/kitty/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.kitty = { 4 | enable = true; 5 | font = { 6 | package = pkgs.nerdfonts; 7 | name = "SauceCodePro Nerd Font Mono"; 8 | }; 9 | settings = { 10 | bold_font = "auto"; 11 | italic_font = "auto"; 12 | bold_italic_font = "auto"; 13 | font_size = 12; 14 | strip_trailing_spaces = "smart"; 15 | enable_audio_bell = "no"; 16 | term = "xterm-256color"; 17 | macos_option_as_alt = "yes"; 18 | scrollback_lines = 10000; 19 | window_padding_width = 4; 20 | 21 | # Catppuccin Colorscheme for Kitty 22 | foreground = "#c6d0f5"; 23 | background = "#303446"; 24 | selection_foreground = "#303446"; 25 | selection_background = "#f2d5cf"; 26 | url_color = "#f2d5cf"; 27 | cursor = "#f2d5cf"; 28 | cursor_text_color = "#303446"; 29 | 30 | active_border_color = "#babbf1"; 31 | inactive_border_color = "#737994"; 32 | bell_border_color = "#e5c890"; 33 | 34 | wayland_titlebar_color = "system"; 35 | macos_titlebar_color = "system"; 36 | 37 | active_tab_foreground = "#232634"; 38 | active_tab_background = "#ca9ee6"; 39 | inactive_tab_foreground = "#c6d0f5"; 40 | inactive_tab_background = "#292c3c"; 41 | tab_bar_background = "#232634"; 42 | 43 | mark1_foreground = "#303446"; 44 | mark1_background = "#babbf1"; 45 | mark2_foreground = "#303446"; 46 | mark2_background = "#ca9ee6"; 47 | mark3_foreground = "#303446"; 48 | mark3_background = "#85c1dc"; 49 | 50 | # black 51 | color0 = "#51576d"; 52 | color8 = "#626880"; 53 | 54 | # red 55 | color1 = "#e78284"; 56 | color9 = "#e78284"; 57 | 58 | # green 59 | color2 = "#a6d189"; 60 | color10 = "#a6d189"; 61 | 62 | # yellow 63 | color3 = "#e5c890"; 64 | color11 = "#e5c890"; 65 | 66 | # blue 67 | color4 = "#8caaee"; 68 | color12 = "#8caaee"; 69 | 70 | # magenta 71 | color5 = "#f4b8e4"; 72 | color13 = "#f4b8e4"; 73 | 74 | # cyan 75 | color6 = "#81c8be"; 76 | color14 = "#81c8be"; 77 | 78 | # white 79 | color7 = "#b5bfe2"; 80 | color15 = "#a5adce"; 81 | }; 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /hosts/cicucci-homelab/configuration.nix: -------------------------------------------------------------------------------- 1 | { config, ... }: 2 | { 3 | # Bootloader. 4 | boot = { 5 | loader = { 6 | systemd-boot.enable = true; 7 | efi.canTouchEfiVariables = true; 8 | }; 9 | }; 10 | 11 | imports = [ 12 | ./hardware-configuration.nix 13 | ../../linux 14 | ]; 15 | 16 | networking = { 17 | hostName = "cicucci-homelab"; 18 | networkmanager = { 19 | enable = true; 20 | }; 21 | }; 22 | 23 | time.timeZone = "America/New_York"; 24 | 25 | # Select internationalisation properties. 26 | i18n.defaultLocale = "en_US.UTF-8"; 27 | 28 | i18n.extraLocaleSettings = { 29 | LC_ADDRESS = "en_US.UTF-8"; 30 | LC_IDENTIFICATION = "en_US.UTF-8"; 31 | LC_MEASUREMENT = "en_US.UTF-8"; 32 | LC_MONETARY = "en_US.UTF-8"; 33 | LC_NAME = "en_US.UTF-8"; 34 | LC_NUMERIC = "en_US.UTF-8"; 35 | LC_PAPER = "en_US.UTF-8"; 36 | LC_TELEPHONE = "en_US.UTF-8"; 37 | LC_TIME = "en_US.UTF-8"; 38 | }; 39 | 40 | age.secrets.homelab_tailscale_key.file = ../../secrets/homelab_tailscale_key.age; 41 | 42 | services.homebridge = { 43 | enable = true; 44 | openFirewall = true; 45 | }; 46 | 47 | services.home-assistant = { 48 | enable = true; 49 | openFirewall = true; 50 | extraComponents = [ 51 | # List of components required to complete the onboarding 52 | "default_config" 53 | "met" 54 | "esphome" 55 | "radio_browser" 56 | "google_translate" 57 | "isal" 58 | # Found on network 59 | "apple_tv" 60 | "brother" 61 | "cast" 62 | "ecobee" 63 | "homekit" 64 | "homekit_controller" 65 | "ipp" 66 | "lutron_caseta" 67 | "plex" 68 | "spotify" 69 | "tplink" 70 | # More integrations 71 | "schlage" 72 | ]; 73 | config = { 74 | # Includes dependencies for a basic setup 75 | # https://www.home-assistant.io/integrations/default_config/ 76 | default_config = { }; 77 | "automation ui" = "!include automations.yaml"; 78 | }; 79 | }; 80 | 81 | networking.firewall = { 82 | allowedTCPPorts = [ 21063 21064 21065 ]; 83 | }; 84 | 85 | my-linux = { 86 | enableNixOptimise = true; 87 | tailscale = { 88 | enable = true; 89 | authkey = config.age.secrets.homelab_tailscale_key.path; 90 | advertiseExitNode = true; 91 | }; 92 | }; 93 | 94 | } 95 | -------------------------------------------------------------------------------- /AGENTS.md: -------------------------------------------------------------------------------- 1 | # Repository Guidelines 2 | 3 | ## Project Structure & Module Organization 4 | Configuration code lives in `hosts/` with paired `configuration.nix` and `home.nix` files per machine. Shared modules sit in `darwin/`, `linux/`, and `home/`, while reusable packages are under `pkgs/`. Templates for new flakes are in `templates/`, assets in `backgrounds/`, and encrypted materials in `secrets/`. Treat `flake.nix` as the single entry point for wiring these pieces together. 5 | 6 | ## Build, Test, and Development Commands 7 | Use `nix develop` (or `direnv allow`) to enter the devshell with pinned tooling. Build a host with `nix build .#darwinConfigurations.personal-laptop.system` or the matching `nixosConfigurations` target, then switch via `darwin-rebuild switch --flake .#personal-laptop` or `sudo nixos-rebuild switch --flake .#cicucci-server`. Run `nix flake check` before pushing to validate module evaluation and package builds. 8 | 9 | ## Coding Style & Naming Conventions 10 | Format Nix code with `nix fmt` (treefmt + `nixpkgs-fmt`). Keep indentation at two spaces, sort attribute sets logically (systems first, then modules), and prefer explicit attribute names over aliases. Host folders use kebab-case (e.g., `cicucci-builder`), module files use snake_case when multiple variants exist, and secrets follow `.age` under `secrets/`. 11 | 12 | ## Testing Guidelines 13 | Rely on `nix flake check` for structural validation and run host builds for any machine you touch. When editing a module shared across platforms, compile at least one Darwin and one NixOS target (for example, `. #darwinConfigurations.work-laptop.system` and `. #nixosConfigurations.cicucci-dns.system`). Capture build output or failure logs in the pull request if tests expose regressions. 14 | 15 | ## Commit & Pull Request Guidelines 16 | Follow the existing history: imperative, present-tense subjects (`Update ccusage`, `Add fd, sd, xh, and navi`). Keep commits scoped to a single concern and mention affected hosts in the body when relevant. Pull requests should summarize the intent, list tested commands, and link any related issues. Include screenshots only when UI-facing templates or assets change. 17 | 18 | ## Secrets & Configuration Safety 19 | All sensitive values are managed through Agenix; edit them with `nix develop` and `agenix -e secrets/.age`. Never commit decrypted secrets or machine-specific tokens. Confirm that new hosts reference existing age keys or document how to provision them. 20 | -------------------------------------------------------------------------------- /home/claude-code/config/CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Claude Code Guidelines 2 | 3 | ## Core Architecture: Functional Core, Imperative Shell (FCIS) 4 | 5 | **Primary Pattern**: Separate pure functions (core) from side effects (shell). 6 | 7 | ### Essential Principles 8 | 9 | 1. **Pure Functional Core** 10 | - No I/O, mutations, or side effects 11 | - Deterministic functions only 12 | - Easy to test and reason about 13 | 14 | 2. **Imperative Shell** 15 | - Handles all I/O (API calls, database, file system) 16 | - Minimal logic, mostly orchestration 17 | - Calls core functions with data 18 | 19 | 3. **Make Invalid States Unrepresentable** 20 | - Use sum types/unions for mutually exclusive states 21 | - Use product types/records for required combinations 22 | - Fail fast at boundaries with validation 23 | 24 | ## Data Modeling 25 | 26 | - **Sum Types**: `type Status = Loading | Success | Error` 27 | - **Product Types**: Required fields grouped together 28 | - **State Machines**: Model business logic as explicit states and transitions 29 | - **Validation**: Transform untrusted input → validated domain types at boundaries 30 | 31 | ## Testing Strategy 32 | 33 | - **Core**: Unit tests with property-based testing when possible 34 | - **Shell**: Integration tests focusing on I/O correctness 35 | - **Boundaries**: Contract tests for external interfaces 36 | 37 | ## Code Organization 38 | 39 | ``` 40 | src/ 41 | ├── core/ # Pure business logic 42 | ├── shell/ # I/O operations 43 | ├── types/ # Domain models 44 | └── boundaries/ # Input validation & transformation 45 | ``` 46 | 47 | ## Key Patterns 48 | 49 | - **Repository Pattern**: Shell handles data access, core operates on domain types 50 | - **Command/Query Separation**: Distinguish data changes from data reads 51 | - **Result Types**: Handle errors explicitly without exceptions in core 52 | - **Dependency Injection**: Shell provides dependencies to core 53 | 54 | ## Security & Performance 55 | 56 | - **Input Validation**: Always at shell boundaries before entering core 57 | - **Least Privilege**: Core functions only get data they need 58 | - **Immutability**: Prefer immutable data structures 59 | - **Lazy Evaluation**: Compute only when needed 60 | 61 | --- 62 | 63 | **Implementation Notes**: 64 | - Apply these patterns regardless of language 65 | - Start with types and data models first 66 | - Keep core functions small and composable 67 | - Test core logic extensively, shell integration carefully -------------------------------------------------------------------------------- /pkgs/codex/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , rustPlatform 4 | , fetchFromGitHub 5 | , installShellFiles 6 | , makeBinaryWrapper 7 | , nix-update-script 8 | , pkg-config 9 | , openssl 10 | , ripgrep 11 | , versionCheckHook 12 | , installShellCompletions ? stdenv.buildPlatform.canExecute stdenv.hostPlatform 13 | , 14 | }: 15 | rustPlatform.buildRustPackage (finalAttrs: { 16 | pname = "codex"; 17 | version = "0.76.0"; 18 | 19 | src = fetchFromGitHub { 20 | owner = "openai"; 21 | repo = "codex"; 22 | tag = "rust-v${finalAttrs.version}"; 23 | hash = "sha256-a6jpYIcfTubSncK1Bxx04X30gkb0J7wi7W6JBXbBBcA="; 24 | }; 25 | 26 | sourceRoot = "${finalAttrs.src.name}/codex-rs"; 27 | 28 | cargoHash = "sha256-fg8OdKKGZ5QjJ/U/7cAFUWNBBa9GbR6OSbYcKeBLP1A="; 29 | 30 | nativeBuildInputs = [ 31 | installShellFiles 32 | makeBinaryWrapper 33 | pkg-config 34 | ]; 35 | 36 | buildInputs = [ openssl ]; 37 | 38 | # NOTE: part of the test suite requires access to networking, local shells, 39 | # apple system configuration, etc. since this is a very fast moving target 40 | # (for now), with releases happening every other day, constantly figuring out 41 | # which tests need to be skipped, or finding workarounds, was too burdensome, 42 | # and in practice not adding any real value. this decision may be reversed in 43 | # the future once this software stabilizes. 44 | doCheck = false; 45 | 46 | postInstall = lib.optionalString installShellCompletions '' 47 | installShellCompletion --cmd codex \ 48 | --bash <($out/bin/codex completion bash) \ 49 | --fish <($out/bin/codex completion fish) \ 50 | --zsh <($out/bin/codex completion zsh) 51 | ''; 52 | 53 | postFixup = '' 54 | wrapProgram $out/bin/codex --prefix PATH : ${lib.makeBinPath [ ripgrep ]} 55 | ''; 56 | 57 | doInstallCheck = true; 58 | nativeInstallCheckInputs = [ versionCheckHook ]; 59 | 60 | passthru = { 61 | updateScript = nix-update-script { 62 | extraArgs = [ 63 | "--version-regex" 64 | "^rust-v(\\d+\\.\\d+\\.\\d+)$" 65 | ]; 66 | }; 67 | }; 68 | 69 | meta = { 70 | description = "Lightweight coding agent that runs in your terminal"; 71 | homepage = "https://github.com/openai/codex"; 72 | changelog = "https://raw.githubusercontent.com/openai/codex/refs/tags/rust-v${finalAttrs.version}/CHANGELOG.md"; 73 | license = lib.licenses.asl20; 74 | mainProgram = "codex"; 75 | platforms = lib.platforms.unix; 76 | }; 77 | }) 78 | -------------------------------------------------------------------------------- /linux/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | with lib; 3 | let 4 | cfg = config.my-linux; 5 | in 6 | { 7 | 8 | imports = [ 9 | ./adguardhome 10 | ./openssh 11 | ./tailscale 12 | ./unbound 13 | ]; 14 | 15 | options.my-linux = { 16 | enableNixOptimise = lib.mkEnableOption "nix auto optimizations"; 17 | 18 | tailscale = lib.mkOption { 19 | description = "tailscale submodule"; 20 | default = { }; 21 | type = types.submodule { 22 | options = { 23 | enable = lib.mkEnableOption "tailscale"; 24 | advertiseExitNode = mkEnableOption "advertise exit node"; 25 | 26 | authkey = mkOption { 27 | type = types.nullOr types.path; 28 | default = null; 29 | example = "/run/secrets/tailscale_key"; 30 | description = '' 31 | A one-time use tailscale key 32 | ''; 33 | }; 34 | }; 35 | }; 36 | }; 37 | 38 | adblocker = lib.mkOption { 39 | description = "adblocker submodule"; 40 | default = { }; 41 | type = types.submodule { 42 | options = { 43 | enable = lib.mkEnableOption "adblocker"; 44 | # Should the adblocker run unbound as the backing dns provider 45 | useUnbound = lib.mkEnableOption "unbound"; 46 | }; 47 | }; 48 | }; 49 | }; 50 | 51 | config = { 52 | nix = { 53 | package = pkgs.nixVersions.stable; 54 | settings = { 55 | auto-optimise-store = cfg.enableNixOptimise; 56 | # Add cache for nix-community, used mainly for neovim nightly 57 | substituters = [ "https://nix-community.cachix.org" ]; 58 | trusted-public-keys = [ 59 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 60 | ]; 61 | }; 62 | gc = optionalAttrs cfg.enableNixOptimise { 63 | automatic = true; 64 | dates = "weekly"; 65 | options = "--delete-older-than 30d"; 66 | }; 67 | # Enable Flakes 68 | extraOptions = '' 69 | experimental-features = nix-command flakes 70 | ${optionalString cfg.enableNixOptimise '' 71 | min-free = ${toString (100 * 1024 * 1024)} 72 | max-free = ${toString (1024 * 1024 * 1024)} 73 | ''} 74 | ''; 75 | }; 76 | 77 | programs.zsh = { 78 | enable = true; 79 | enableCompletion = false; 80 | promptInit = ""; 81 | }; 82 | 83 | users.defaultUserShell = pkgs.zsh; 84 | 85 | system.stateVersion = "22.05"; 86 | }; 87 | 88 | } 89 | -------------------------------------------------------------------------------- /pkgs/kotlin-lsp/default.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , fetchurl 4 | , makeWrapper 5 | , unzip 6 | }: 7 | 8 | let 9 | # Define binary information for each platform 10 | version = "261.13587.0"; 11 | sources = { 12 | "aarch64-darwin" = { 13 | url = "https://download-cdn.jetbrains.com/kotlin-lsp/${version}/kotlin-lsp-${version}-mac-aarch64.zip"; 14 | sha256 = "0v7fzfp6lc2gb0awnvd6lr31dwb8hj56j8vdw5pr1kr95fr2isnl"; 15 | }; 16 | "x86_64-darwin" = { 17 | url = "https://download-cdn.jetbrains.com/kotlin-lsp/${version}/kotlin-lsp-${version}-mac-x64.zip"; 18 | sha256 = "18v40m6sfwizyldrgz3d68nchn69l6p4prb0c0i2rfly48kjz5x3"; 19 | }; 20 | "x86_64-linux" = { 21 | url = "https://download-cdn.jetbrains.com/kotlin-lsp/${version}/kotlin-lsp-${version}-linux-x64.zip"; 22 | sha256 = "1v43dvncm4jyf49r9yzzvk07aylv57lgrbi6pgd1zmmh1kkx43nw"; 23 | }; 24 | "aarch64-linux" = { 25 | url = "https://download-cdn.jetbrains.com/kotlin-lsp/${version}/kotlin-lsp-${version}-linux-aarch64.zip"; 26 | sha256 = "0lfny6ll9dgfgwb4im1ys0di018xn157ypmr60n5wv701w0fpp6i"; 27 | }; 28 | }; 29 | 30 | # Select the appropriate source for the current system 31 | selectedSource = sources.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); 32 | in 33 | stdenv.mkDerivation rec { 34 | pname = "kotlin-lsp"; 35 | inherit version; 36 | 37 | src = fetchurl { 38 | inherit (selectedSource) url sha256; 39 | }; 40 | 41 | nativeBuildInputs = [ 42 | makeWrapper 43 | unzip 44 | ]; 45 | 46 | unpackPhase = '' 47 | runHook preUnpack 48 | 49 | unzip $src 50 | 51 | runHook postUnpack 52 | ''; 53 | 54 | dontBuild = true; 55 | 56 | installPhase = '' 57 | runHook preInstall 58 | 59 | # Create output directories 60 | mkdir -p $out/bin $out/share/kotlin-lsp 61 | 62 | # Copy all files to share directory 63 | cp -r * $out/share/kotlin-lsp/ 64 | 65 | # Make the shell script executable 66 | chmod +x $out/share/kotlin-lsp/kotlin-lsp.sh 67 | 68 | # Make the bundled Java executable 69 | chmod +x $out/share/kotlin-lsp/jre/Contents/Home/bin/java 70 | 71 | # Create wrapper script that points to the kotlin-lsp.sh script 72 | makeWrapper $out/share/kotlin-lsp/kotlin-lsp.sh $out/bin/kotlin-lsp 73 | 74 | runHook postInstall 75 | ''; 76 | 77 | meta = with lib; { 78 | description = "Kotlin Language Server Protocol implementation"; 79 | homepage = "https://github.com/Kotlin/kotlin-lsp"; 80 | license = licenses.asl20; 81 | platforms = platforms.all; 82 | mainProgram = "kotlin-lsp"; 83 | }; 84 | } 85 | -------------------------------------------------------------------------------- /secrets/secrets.nix: -------------------------------------------------------------------------------- 1 | # This file is not imported into your NixOS configuration. It is only used for the agenix CLI. 2 | # agenix use the public keys defined in this file to encrypt the secrets. 3 | # and users can decrypt the secrets by any of the corresponding private keys. 4 | 5 | let 6 | # get user's ssh public key by command: 7 | # cat ~/.ssh/id_ed25519.pub 8 | # if you do not have one, you can generate it by command: 9 | # ssh-keygen -t ed25519 10 | cicucci-desktop-fmoda3 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKKKgYlOjtFHLxJUqoQiqvoad6G1yNNXwI5/G1NIwu27"; 11 | cicucci-laptop-fmoda3 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCz3Wfp4pIEqpgegM4FCrEiehQEnwDXmTQmpL2+QUKerDQEep3bJYS2NKqHeMotuCgSjbhnObPPxpT7Vr8bq/NFdfLbuqFILx7mCCmzvWB3A050qQkwLuE00PEYmdsH25OhztgTMPvHMhtw1gNJCAyXtvI3DN0DCJKDRJFWOp/Kj70hxHNsQogPbBBgqzfF4j2aYC7X7h3bXHzOc4lKFhZ+7xIj0yGenSSw9PM9PUvEMlFL53uG4QsUisIOvs7IptXjOkdWAug/bRX+XpEFYmCEp+1H2UqZVRNmIV6Fa2FPXqRILuWOsCALmYV5oRk9MgPbufdJ9CHvmu1SMCJ/mlbt8jicmOvgdzdRBmYiWfjtZNh929pP8c9BgFCNt4efZ5qqynlUzywuO4agw1iOXi4KppPLbb7UisnMo9+NtEjHXtneRJnPgYi+KmNyS/7O1/9egDt64bB9+ZkGjajeOVELxcEvwrHupHeLb3N3gC7lkAoRwmGHWxHKcyDS6kUQRC0="; 12 | cicucci-server-fmoda3 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN8fct8sqoXsqMJFaiYZxKxC4IPKDWXL+ZGfW387RNKo"; 13 | cicucci-homelab-fmoda3 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMbsadR1/6wz//uJ7fjuQnyBd3shjFcaLl5wlhSaFD+4"; 14 | work-laptop-fmoda3 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCYl3aVZjHTsKEboUS7r1YYAPdb39SKiIz1VtIVTLARR1goxg34Zbq0drxYyToBD151UmQ8Rs8Ybv3WVYQISdp9j4B8ZVjijLdL1SyajMAOztz5/3vlbEU9+tZUnd9VxEi7bRB31uFpaAjCYghHDaY22S8UzRqg0xZfQc/MEa7rgbXP1gxEeolEOJYohSk6ko3X6yAW15vd8mmJCThbtYbLkp31Yhdbo0KnyBIQo7or8IK5qbjHFdMwveYh29QXur7fZ+bDvFWUvW6DnrBkvMSZAymDACiOYUOenqmmdIhzyC3QN2RosABF3tB2rBkPb4WhfTQbyx8mYSZLkl5mUuGhMD0wXhmmcaoRV3miT807D1lDe9+bxcXnZEQSzTpPUQMgm12F2LkWnF7eZDTHcVZRhYUxrepHFHl7pq2N50LVq5ThNF+KImc1yqb7X0646cHibn9TxB2lKN8miACdepGMyNYfNmuJVxyoHh9y2MNhUohFc6QwvaEUtjFgj1jJtW8="; 15 | users = [ cicucci-desktop-fmoda3 cicucci-laptop-fmoda3 cicucci-server-fmoda3 cicucci-homelab-fmoda3 work-laptop-fmoda3 ]; 16 | 17 | # get system's ssh public key by command: 18 | # cat /etc/ssh/ssh_host_ed25519_key.pub 19 | cicucci-dns = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGfR61TZ2/54tN4NJXhp9+NJRw0gIELXm0c+nzpACLKo"; 20 | cicucci-homelab = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFjpYheKaxVXLCQH4hQ2Y9uCmWuWfHPaWwEaVovNr2Am"; 21 | systems = [ cicucci-dns cicucci-homelab ]; 22 | 23 | all = users ++ systems; 24 | work = [ work-laptop-fmoda3 ]; 25 | personal = [ cicucci-desktop-fmoda3 cicucci-laptop-fmoda3 cicucci-server-fmoda3 cicucci-homelab-fmoda3 cicucci-dns cicucci-homelab ]; 26 | in 27 | { 28 | "dns_tailscale_key.age".publicKeys = [ cicucci-dns ]; 29 | "homelab_tailscale_key.age".publicKeys = [ cicucci-homelab cicucci-homelab-fmoda3 ]; 30 | "flaggy_token.age".publicKeys = work; 31 | } 32 | -------------------------------------------------------------------------------- /claude/CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Claude Code Global Guidelines 2 | 3 | My name is Frank. 4 | 5 | This document serves as the table of contents for all Claude Code guidelines. Claude should read and follow all linked documents when working on any project. 6 | 7 | ## Architecture & Design Patterns 8 | 9 | - [Functional Core, Imperative Shell](fcis-architecture.md) - **PRIMARY ARCHITECTURE PATTERN** 10 | - All projects must follow FCIS principles 11 | - Pure functional core with imperative shell for I/O 12 | - Making invalid states unrepresentable 13 | 14 | ## Language-Specific Guidelines 15 | 16 | - [Kotlin Guidelines](kotlin-guidelines.md) 17 | - Coroutines best practices 18 | - Data class and sealed class patterns 19 | - Kotlin-specific FCIS implementation 20 | 21 | - [TypeScript Guidelines](typescript-guidelines.md) 22 | - Type-safe functional patterns 23 | - Discriminated unions and exhaustive checking 24 | - Frontend/backend TypeScript conventions 25 | 26 | - [Elixir Guidelines](elixir-guidelines.md) 27 | - OTP design principles with FCIS 28 | - GenServer patterns in the imperative shell 29 | - Pattern matching best practices 30 | 31 | ## Domain Modeling 32 | 33 | - [Data Modeling Principles](data-modeling.md) 34 | - Sum types and product types 35 | - State machine modeling 36 | - Domain-driven design with functional programming 37 | 38 | ## Testing & Quality 39 | 40 | - [Testing Strategy](testing-strategy.md) 41 | - Property-based testing for functional core 42 | - Integration testing for imperative shell 43 | - Test data generation patterns 44 | 45 | ## Project Templates 46 | 47 | - [Project Structure](project-structure.md) 48 | - Standard directory layouts 49 | - Module boundaries and dependencies 50 | - Build configuration templates 51 | 52 | ## Code Style 53 | 54 | - [Formatting and Naming](code-style.md) 55 | - Consistent naming conventions 56 | - Formatting rules per language 57 | - Documentation standards 58 | 59 | ## Performance & Infrastructure 60 | 61 | - [API Design Patterns](api-design.md) 62 | - RESTful and GraphQL API patterns 63 | - Request/response transformations 64 | - Versioning strategies 65 | 66 | - [Database Patterns](database-patterns.md) 67 | - Repository pattern implementation 68 | - Transaction management 69 | - Migration strategies 70 | - Query optimization 71 | 72 | - [Performance Patterns](performance-patterns.md) 73 | - Memoization and caching strategies 74 | - Lazy evaluation techniques 75 | - Concurrency patterns 76 | - Monitoring and profiling 77 | 78 | - [Security Patterns](security-patterns.md) 79 | - Input validation and sanitization 80 | - Authentication and authorization 81 | - Cryptography best practices 82 | - Privacy and compliance 83 | 84 | --- 85 | 86 | **Important**: When starting any new project or feature, Claude must: 87 | 1. Read all relevant linked documents 88 | 2. Apply FCIS architecture as the default pattern 89 | 3. Use language-specific guidelines for implementation details 90 | 4. Ensure data models make invalid states unrepresentable -------------------------------------------------------------------------------- /home/nvim/config/lua/gitsigns-config.lua: -------------------------------------------------------------------------------- 1 | require("gitsigns").setup({ 2 | on_attach = function(bufnr) 3 | local gitsigns = require("gitsigns") 4 | 5 | -- Navigation 6 | require("which-key").add({ 7 | { 8 | "]g", 9 | function() 10 | if vim.wo.diff then 11 | vim.cmd.normal({ "]c", bang = true }) 12 | else 13 | gitsigns.nav_hunk("next") 14 | end 15 | end, 16 | desc = "Gitsigns: Next hunk", 17 | icon = "󰒭", 18 | }, 19 | { 20 | "[g", 21 | function() 22 | if vim.wo.diff then 23 | vim.cmd.normal({ "[c", bang = true }) 24 | else 25 | gitsigns.nav_hunk("prev") 26 | end 27 | end, 28 | desc = "Gitsigns: Previous hunk", 29 | icon = "󰒮", 30 | }, 31 | }) 32 | 33 | -- Actions 34 | require("which-key").add({ 35 | { "g", group = "Git", icon = "" }, 36 | { "gs", gitsigns.stage_hunk, desc = "Gitsigns: Stage hunk", icon = "" }, 37 | { "gr", gitsigns.reset_hunk, desc = "Gitsigns: Reset hunk", icon = "" }, 38 | { 39 | "gs", 40 | function() 41 | gitsigns.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) 42 | end, 43 | mode = { "v" }, 44 | desc = "Gitsigns: Stage hunk (visual)", 45 | icon = "", 46 | }, 47 | { 48 | "gr", 49 | function() 50 | gitsigns.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) 51 | end, 52 | mode = { "v" }, 53 | desc = "Gitsigns: Reset hunk (visual)", 54 | icon = "", 55 | }, 56 | { "gS", gitsigns.stage_buffer, desc = "Gitsigns: Stage buffer", icon = "" }, 57 | { "gR", gitsigns.reset_buffer, desc = "Gitsigns: Reset buffer", icon = "" }, 58 | { "gp", gitsigns.preview_hunk, desc = "Gitsigns: Preview hunk", icon = "" }, 59 | { "gi", gitsigns.preview_hunk_inline, desc = "Gitsigns: Preview hunk inline", icon = "" }, 60 | { 61 | "gb", 62 | function() 63 | gitsigns.blame_line({ full = true }) 64 | end, 65 | desc = "Gitsigns: Blame line", 66 | icon = "", 67 | }, 68 | { "gd", gitsigns.diffthis, desc = "Gitsigns: Diff this", icon = "" }, 69 | { 70 | "gD", 71 | function() 72 | gitsigns.diffthis("~") 73 | end, 74 | desc = "Gitsigns: Diff this (cached)", 75 | icon = "", 76 | }, 77 | { 78 | "gQ", 79 | function() 80 | gitsigns.setqflist("all") 81 | end, 82 | desc = "Gitsigns: Set qflist", 83 | icon = "󱖫", 84 | }, 85 | }) 86 | 87 | -- Toggles 88 | require("which-key").add({ 89 | { "gt", group = "Toggle", icon = "󰔡" }, 90 | { 91 | "gtb", 92 | gitsigns.toggle_current_line_blame, 93 | desc = "Gitsigns: Toggle current line blame", 94 | icon = "", 95 | }, 96 | { "gtd", gitsigns.toggle_deleted, desc = "Gitsigns: Toggle deleted", icon = "" }, 97 | { "gtw", gitsigns.toggle_word_diff, desc = "Gitsigns: Toggle word diff", icon = "" }, 98 | }) 99 | 100 | -- Text object 101 | require("which-key").add({ 102 | { "gi", gitsigns.select_hunk, desc = "Gitsigns: Select hunk", icon = "󰒅", mode = { "o", "x" } }, 103 | }) 104 | end, 105 | }) 106 | -------------------------------------------------------------------------------- /home/tmux/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.tmux = { 4 | enable = true; 5 | shortcut = "a"; 6 | baseIndex = 1; 7 | terminal = "screen-256color"; 8 | keyMode = "vi"; 9 | historyLimit = 10000; 10 | escapeTime = 1; 11 | customPaneNavigationAndResize = true; 12 | resizeAmount = 5; 13 | 14 | plugins = with pkgs.tmuxPlugins; [ 15 | sensible 16 | ]; 17 | 18 | extraConfig = '' 19 | # Set default terminal 20 | set -g default-terminal "tmux-256color" 21 | 22 | # Set theme 23 | set -g @catppuccin_flavor 'frappe' # latte, frappe, macchiato or mocha 24 | set -g @catppuccin_window_status_style "rounded" 25 | set -g @catppuccin_window_text " #{b:pane_current_path}" 26 | set -g @catppuccin_window_current_text " #{b:pane_current_path}" 27 | run-shell ${pkgs.tmuxPlugins.catppuccin}/share/tmux-plugins/catppuccin/catppuccin.tmux 28 | 29 | # Need to override sensible 30 | set -g default-command '$SHELL' 31 | 32 | # splitting panes 33 | # START:panesplit 34 | bind | split-window -h 35 | bind - split-window -v 36 | # END:panesplit 37 | 38 | # Quick pane selection 39 | # START:panetoggle 40 | bind -r C-h select-window -t :- 41 | bind -r C-l select-window -t :+ 42 | # END:panetoggle 43 | 44 | # mouse support - set to on if you want to use the mouse 45 | # START:mouse 46 | setw -g mouse off 47 | # END:mouse 48 | 49 | # enable activity alerts 50 | #START:activity 51 | setw -g monitor-activity on 52 | set -g visual-activity on 53 | setw -g window-status-activity-style none 54 | #END:activity 55 | 56 | # Ring the bell if any background window rang a bell 57 | set -g bell-action any 58 | 59 | # Keep your finger on ctrl, or don't 60 | bind-key ^D detach-client 61 | 62 | # easily toggle synchronization (mnemonic: e is for echo) 63 | # sends input to all panes in a given window. 64 | bind e setw synchronize-panes 65 | 66 | # color scheme (styled as vim-powerline) 67 | set -g status-right-length 100 68 | set -g status-left-length 100 69 | set -g status-left "" 70 | set -g status-right "#{E:@catppuccin_status_application}" 71 | set -agF status-right "#{E:@catppuccin_status_cpu}" 72 | set -ag status-right "#{E:@catppuccin_status_session}" 73 | set -ag status-right "#{E:@catppuccin_status_uptime}" 74 | set -agF status-right "#{E:@catppuccin_status_battery}" 75 | 76 | # Screen like binding for last window 77 | bind C-a last-window 78 | 79 | # Log output to a text file on demand 80 | # START:pipe-pane 81 | bind P pipe-pane -o "cat >>~/#W.log" \; display "Toggled logging to ~/#W.log" 82 | # END:pipe-pane 83 | 84 | # Neovim color compatibility 85 | set-option -sa terminal-overrides ',xterm-256color:RGB' 86 | 87 | # Auto rename windows to directory 88 | set-option -g status-interval 1 89 | set-option -g automatic-rename on 90 | set-option -g automatic-rename-format ' #{b:pane_current_path}' 91 | 92 | run-shell ${pkgs.tmuxPlugins.cpu}/share/tmux-plugins/cpu/cpu.tmux 93 | run-shell ${pkgs.tmuxPlugins.battery}/share/tmux-plugins/battery/battery.tmux 94 | ''; 95 | }; 96 | } 97 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Repository Overview 6 | 7 | This is a comprehensive Nix configuration repository managing multiple machines (macOS and Linux) using Nix Flakes. It includes system configurations, Home Manager user configurations, custom packages, and deployment automation. 8 | 9 | ## Common Commands 10 | 11 | ### System Management 12 | ```bash 13 | # Build and switch configurations 14 | darwin-rebuild switch --flake ".#cicucci-desktop" # macOS 15 | sudo nixos-rebuild switch --flake ".#cicucci-dns" # Linux 16 | 17 | # Update flake inputs 18 | nix flake update 19 | 20 | # Enter development environment 21 | nix develop 22 | ``` 23 | 24 | ### Code Quality 25 | ```bash 26 | format # Format Nix files with nixpkgs-fmt 27 | lint # Run statix linter 28 | nix fmt # Alternative formatting 29 | ``` 30 | 31 | ### Image Building (devshell commands) 32 | ```bash 33 | create-aarch64-iso # ARM64 installation ISO 34 | create-x86_64-iso # x86_64 installation ISO 35 | create-dns-sd # Raspberry Pi SD card image 36 | ``` 37 | 38 | ### Secrets Management 39 | ```bash 40 | age-edit # Edit encrypted secrets 41 | age-rekey # Rekey all secrets 42 | ``` 43 | 44 | ### Deployment 45 | ```bash 46 | colmena apply # Deploy to remote systems 47 | ``` 48 | 49 | ## Architecture 50 | 51 | ### Core Structure 52 | - **flake.nix**: Main configuration defining all system outputs 53 | - **hosts/**: Machine-specific configurations organized by hostname 54 | - **home/**: Home Manager modules for user-level tools and applications 55 | - **darwin/**: macOS-specific system configurations 56 | - **linux/**: nixos-specific system configurations 57 | - **pkgs/**: Custom package definitions and overlays 58 | - **secrets/**: Age-encrypted secrets management 59 | 60 | ### System Types 61 | - **darwinConfigurations**: macOS systems (cicucci-desktop, cicucci-laptop, work-laptop) 62 | - **nixosConfigurations**: Linux systems (cicucci-dns, cicucci-homelab, cicucci-builder) 63 | - **images**: Bootable installation media 64 | 65 | ### Package Management 66 | - Custom packages defined in `pkgs/` are available as `pkgs.packageName` 67 | - Uses overlays to integrate custom packages with nixpkgs 68 | - Supports multiple nixpkgs channels (stable, unstable, master) 69 | 70 | ### Multi-Architecture Support 71 | - Supports ARM64 and x86_64 architectures 72 | - Uses remote builders for cross-compilation 73 | - Specialized configurations for different hardware types 74 | 75 | ## Key Features 76 | 77 | ### Configuration Modularity 78 | - Shared modules in `home/` and `darwin/` directories 79 | - Host-specific configurations compose shared modules 80 | - Conditional configurations based on machine type (work vs personal) 81 | 82 | ### Secrets Management 83 | - Uses agenix for encrypted secrets 84 | - Secrets are per-machine and can be shared across machines 85 | - Automatic rekeying when keys change 86 | 87 | ### Remote Deployment 88 | - Uses colmena for remote system management 89 | - Configurations for multiple remote systems 90 | - Automated deployment pipelines 91 | 92 | ### Development Environment 93 | - Direnv integration for automatic environment loading 94 | - Pre-commit hooks for code quality 95 | - Development shells with necessary tools (nixd, statix, agenix) 96 | -------------------------------------------------------------------------------- /home/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | with lib; 3 | let 4 | cfg = config.my-home; 5 | in 6 | { 7 | 8 | imports = [ 9 | ./bat 10 | ./btop 11 | ./claude-code 12 | ./codex 13 | ./delta 14 | ./direnv 15 | ./eza 16 | ./fzf 17 | ./games 18 | ./gh 19 | ./ghostty 20 | ./git 21 | ./jq 22 | # ./kitty 23 | ./lazygit 24 | ./navi 25 | ./nh 26 | ./nvim 27 | ./secrets 28 | ./starship 29 | ./tmux 30 | ./yazi 31 | ./zoxide 32 | ./zsh 33 | ]; 34 | 35 | options.my-home = { 36 | includeFonts = lib.mkEnableOption "fonts"; 37 | useNeovim = lib.mkEnableOption "neovim"; 38 | isWork = lib.mkEnableOption "work profile"; 39 | includeGames = lib.mkEnableOption "games"; 40 | flake = lib.mkOption { 41 | description = "Flake string to use for nh"; 42 | default = ""; 43 | type = types.str; 44 | }; 45 | }; 46 | 47 | config = { 48 | # Home Manager needs a bit of information about you and the 49 | # paths it should manage. 50 | home = { 51 | packages = with pkgs; let 52 | commonPackages = [ 53 | # command line utilities 54 | ack 55 | ccusage 56 | comma 57 | curl 58 | duf 59 | dust 60 | fd 61 | htop 62 | gping 63 | neofetch 64 | nh 65 | nix-cleanup 66 | nodejs 67 | playwright-mcp 68 | procs 69 | ripgrep 70 | sd 71 | tldr 72 | tokei 73 | typst 74 | wget 75 | xh 76 | ]; 77 | fontPackages = [ 78 | # Fonts 79 | cozette 80 | nerd-fonts.fira-code 81 | nerd-fonts.fira-mono 82 | nerd-fonts.inconsolata 83 | nerd-fonts.iosevka 84 | nerd-fonts.iosevka-term 85 | nerd-fonts.iosevka-term-slab 86 | nerd-fonts.monaspace 87 | nerd-fonts.terminess-ttf 88 | monocraft 89 | scientifica 90 | ]; 91 | vimPackage = [ vim ]; 92 | workPackages = [ 93 | # Work packages 94 | android-tools 95 | autossh 96 | awscli2 97 | colima 98 | docker 99 | docker-compose 100 | docker-credential-helpers 101 | heroku 102 | postgresql 103 | toast.oktoast 104 | toast.toast-services 105 | ]; 106 | in 107 | commonPackages 108 | ++ (lib.optionals cfg.includeFonts fontPackages) 109 | ++ (lib.optionals (!cfg.useNeovim) vimPackage) 110 | ++ (lib.optionals cfg.isWork workPackages); 111 | }; 112 | 113 | fonts.fontconfig.enable = cfg.includeFonts; 114 | 115 | programs.nix-index.enable = true; 116 | 117 | # This value determines the Home Manager release that your 118 | # configuration is compatible with. This helps avoid breakage 119 | # when a new Home Manager release introduces backwards 120 | # incompatible changes. 121 | # 122 | # You can update Home Manager without changing this value. See 123 | # the Home Manager release notes for a list of state version 124 | # changes in each release. 125 | home.stateVersion = "21.05"; 126 | }; 127 | 128 | } 129 | -------------------------------------------------------------------------------- /home/claude-code/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, pkgs, ... }: 2 | let 3 | cfg = config.my-home; 4 | 5 | commonEnv = { 6 | CLAUDE_CODE_DISABLE_FEEDBACK_SURVEY = "1"; 7 | }; 8 | in 9 | { 10 | programs.claude-code = { 11 | enable = true; 12 | settings = { 13 | hooks = { 14 | Stop = [ 15 | { 16 | matcher = ""; 17 | hooks = [ 18 | { 19 | type = "command"; 20 | command = "afplay /System/Library/Sounds/Funk.aiff"; 21 | } 22 | ]; 23 | } 24 | ]; 25 | Notification = [ 26 | { 27 | matcher = ""; 28 | hooks = [ 29 | { 30 | type = "command"; 31 | command = "afplay /System/Library/Sounds/Funk.aiff"; 32 | } 33 | ]; 34 | } 35 | ]; 36 | }; 37 | statusLine = { 38 | type = "command"; 39 | command = "~/.claude/statusline.sh"; 40 | }; 41 | env = commonEnv; 42 | } // lib.optionalAttrs cfg.isWork { 43 | env = commonEnv // { 44 | CLAUDE_CODE_USE_BEDROCK = "1"; 45 | CLAUDE_CODE_SKIP_BEDROCK_AUTH = "1"; 46 | ANTHROPIC_BEDROCK_BASE_URL = "https://llm-proxy.prod-build.int.toasttab.com/bedrock"; 47 | ANTHROPIC_DEFAULT_OPUS_MODEL = "global.anthropic.claude-opus-4-5-20251101-v1:0"; 48 | ANTHROPIC_DEFAULT_SONNET_MODEL = "global.anthropic.claude-sonnet-4-5-20250929-v1:0"; 49 | ANTHROPIC_DEFAULT_HAIKU_MODEL = "global.anthropic.claude-haiku-4-5-20251001-v1:0"; 50 | CLAUDE_CODE_ENABLE_TELEMETRY = "1"; 51 | OTEL_METRICS_EXPORTER = "otlp"; 52 | OTEL_LOGS_EXPORTER = "otlp"; 53 | OTEL_EXPORTER_OTLP_PROTOCOL = "http/protobuf"; 54 | OTEL_EXPORTER_OTLP_ENDPOINT = "https://bedrock-otel-collector.build.eng.toasttab.com"; 55 | OTEL_RESOURCE_ATTRIBUTES = "department=engineering,team.id=paas,user_email=frank@toasttab.com,cost_center=default,organization=default"; 56 | }; 57 | apiKeyHelper = "${pkgs.toast.toastApiKeyHelper}/bin/toastApiKeyHelper"; 58 | extraKnownMarketplaces = { 59 | "toast-marketplace" = { 60 | source = { 61 | source = "git"; 62 | url = "git@github.toasttab.com:toasttab/claude-marketplace.git"; 63 | }; 64 | }; 65 | }; 66 | enabledPlugins = { 67 | "toast-developer@toast-marketplace" = true; 68 | "toast-backend-development@toast-marketplace" = true; 69 | }; 70 | }; 71 | memory.source = ./config/CLAUDE.md; 72 | agentsDir = ./config/agents; 73 | commandsDir = ./config/commands; 74 | mcpServers = { 75 | context7 = { 76 | type = "http"; 77 | url = "https://mcp.context7.com/mcp"; 78 | }; 79 | deepwiki = { 80 | type = "http"; 81 | url = "https://mcp.deepwiki.com/mcp"; 82 | }; 83 | sequential-thinking = { 84 | type = "http"; 85 | url = "https://remote.mcpservers.org/sequentialthinking/mcp"; 86 | }; 87 | } // lib.optionalAttrs cfg.isWork { 88 | atlassian = { 89 | type = "sse"; 90 | url = "https://mcp.atlassian.com/v1/sse"; 91 | }; 92 | buffet = { 93 | command = "npx"; 94 | args = [ 95 | "--registry=https://artifactory.eng.toasttab.com/artifactory/api/npm/toast_npm/" 96 | "@toasttab/buffet-mcp-server@next" 97 | ]; 98 | }; 99 | figma = { 100 | type = "http"; 101 | url = "http://127.0.0.1:3845/mcp"; 102 | }; 103 | }; 104 | }; 105 | 106 | home = { 107 | file = { 108 | ".claude/statusline.sh" = { 109 | source = ./config/statusline.sh; 110 | executable = true; 111 | }; 112 | }; 113 | }; 114 | } 115 | -------------------------------------------------------------------------------- /home/claude-code/config/agents/code-reviewer.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: code-reviewer 3 | description: Use this agent when you need expert code review feedback on recently written code. This agent analyzes code for best practices, potential bugs, performance issues, and architectural concerns. It provides actionable suggestions for improvement while considering project-specific patterns and standards. Examples:\n\n\nContext: The user wants to review a function they just wrote.\nuser: "I just implemented a new authentication service. Can you review it?"\nassistant: "I'll use the code-reviewer agent to analyze your authentication service implementation."\n\nSince the user has written new code and wants feedback, use the Task tool to launch the code-reviewer agent.\n\n\n\n\nContext: The user has completed a feature and wants a review.\nuser: "I've finished the payment processing module"\nassistant: "Let me review your payment processing module using the code-reviewer agent to ensure it follows best practices."\n\nThe user has completed code that needs review, so launch the code-reviewer agent to provide feedback.\n\n 4 | color: purple 5 | --- 6 | 7 | You are an expert software engineer specializing in code review with deep knowledge of software design patterns, security best practices, and performance optimization. Your role is to provide thorough, constructive feedback on recently written code. 8 | 9 | When reviewing code, you will: 10 | 11 | 1. **Analyze Code Quality** 12 | - Identify potential bugs, edge cases, and error conditions 13 | - Check for proper error handling and validation 14 | - Evaluate code readability and maintainability 15 | - Assess naming conventions and code organization 16 | 17 | 2. **Apply Architecture Principles** 18 | - Verify adherence to Functional Core, Imperative Shell (FCIS) pattern where applicable 19 | - Ensure proper separation of concerns 20 | - Check that pure functions remain side-effect free 21 | - Validate that I/O operations are properly isolated in the shell layer 22 | 23 | 3. **Security Review** 24 | - Identify potential security vulnerabilities 25 | - Ensure proper input validation at boundaries 26 | - Check for secure handling of sensitive data 27 | - Verify authentication and authorization patterns 28 | 29 | 4. **Performance Considerations** 30 | - Identify potential performance bottlenecks 31 | - Suggest optimizations where appropriate 32 | - Check for efficient data structures and algorithms 33 | - Consider scalability implications 34 | 35 | 5. **Best Practices Compliance** 36 | - Ensure code follows established patterns in the codebase 37 | - Verify proper use of language-specific idioms 38 | - Check test coverage and suggest additional test cases 39 | - Validate documentation and comments 40 | 41 | **Review Process**: 42 | 1. First, understand the code's purpose and context 43 | 2. Perform a systematic review covering all aspects above 44 | 3. Prioritize findings by severity (critical → major → minor → suggestions) 45 | 4. Provide specific, actionable feedback with code examples when helpful 46 | 5. Acknowledge what's done well before suggesting improvements 47 | 48 | **Output Format**: 49 | - Start with a brief summary of what the code does 50 | - List findings organized by severity 51 | - For each finding, explain the issue, why it matters, and how to fix it 52 | - Include code snippets to illustrate suggestions 53 | - End with positive observations about the code 54 | 55 | **Important Guidelines**: 56 | - Be constructive and educational in your feedback 57 | - Focus on the most recently written or modified code unless asked otherwise 58 | - Consider project-specific patterns from CLAUDE.md files 59 | - Ask for clarification if the code's intent is unclear 60 | - Balance thoroughness with practicality - not every minor issue needs fixing 61 | - Respect existing architectural decisions while suggesting improvements 62 | -------------------------------------------------------------------------------- /home/gh/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | programs.gh = { 4 | enable = true; 5 | settings = { 6 | git_protocol = "ssh"; 7 | }; 8 | extensions = [ 9 | pkgs.gh-contribs 10 | pkgs.gh-eco 11 | pkgs.gh-f 12 | pkgs.gh-notify 13 | ]; 14 | }; 15 | 16 | programs.gh-dash = { 17 | enable = true; 18 | settings = { 19 | prSections = [ 20 | { 21 | title = "My Pull Requests"; 22 | filters = "is:open author:@me"; 23 | type = null; 24 | } 25 | { 26 | title = "Needs My Review"; 27 | filters = "is:open review-requested:@me"; 28 | type = null; 29 | } 30 | { 31 | title = "Involved"; 32 | filters = "is:open involves:@me -author:@me"; 33 | type = null; 34 | } 35 | ]; 36 | issuesSections = [ 37 | { 38 | title = "My Issues"; 39 | filters = "is:open author:@me"; 40 | } 41 | { 42 | title = "Assigned"; 43 | filters = "is:open assignee:@me"; 44 | } 45 | { 46 | title = "Involved"; 47 | filters = "is:open involves:@me -author:@me"; 48 | } 49 | ]; 50 | repo = { 51 | branchesRefetchIntervalSeconds = 30; 52 | prsRefetchIntervalSeconds = 60; 53 | }; 54 | defaults = { 55 | preview = { 56 | open = true; 57 | width = 50; 58 | }; 59 | prsLimit = 20; 60 | prApproveComment = "LGTM"; 61 | issuesLimit = 20; 62 | view = "prs"; 63 | layout = { 64 | prs = { 65 | updatedAt = { 66 | width = 5; 67 | }; 68 | createdAt = { 69 | width = 5; 70 | }; 71 | repo = { 72 | width = 20; 73 | }; 74 | author = { 75 | width = 15; 76 | }; 77 | authorIcon = { 78 | hidden = false; 79 | }; 80 | assignees = { 81 | width = 20; 82 | hidden = true; 83 | }; 84 | base = { 85 | width = 15; 86 | hidden = true; 87 | }; 88 | lines = { 89 | width = 15; 90 | }; 91 | }; 92 | issues = { 93 | updatedAt = { 94 | width = 5; 95 | }; 96 | createdAt = { 97 | width = 5; 98 | }; 99 | repo = { 100 | width = 15; 101 | }; 102 | creator = { 103 | width = 10; 104 | }; 105 | creatorIcon = { 106 | hidden = false; 107 | }; 108 | assignees = { 109 | width = 20; 110 | hidden = true; 111 | }; 112 | }; 113 | }; 114 | refetchIntervalMinutes = 30; 115 | }; 116 | keybindings = { 117 | universal = [ ]; 118 | issues = [ ]; 119 | prs = [ ]; 120 | branches = [ ]; 121 | }; 122 | repoPaths = { }; 123 | theme = { 124 | colors = { 125 | text = { 126 | primary = "#c6d0f5"; 127 | secondary = "#8caaee"; 128 | inverted = "#232634"; 129 | faint = "#b5bfe2"; 130 | warning = "#e5c890"; 131 | success = "#a6d189"; 132 | error = "#e78284"; 133 | }; 134 | background = { 135 | selected = "#414559"; 136 | }; 137 | border = { 138 | primary = "#8caaee"; 139 | secondary = "#51576d"; 140 | faint = "#414559"; 141 | }; 142 | }; 143 | }; 144 | pager = { 145 | diff = ""; 146 | }; 147 | confirmQuit = false; 148 | showAuthorIcons = true; 149 | smartFilteringAtLaunch = true; 150 | }; 151 | }; 152 | } 153 | -------------------------------------------------------------------------------- /home/claude-code/config/agents/systems-architect.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: systems-architect 3 | description: Use this agent when you need to design and plan the implementation of new functionality, from simple bug fixes to complex system architectures. This includes analyzing requirements, proposing technical solutions, identifying components and their interactions, and creating implementation roadmaps. Examples:\n\n\nContext: User needs to add a new feature to their application.\nuser: "I need to add a notification system that sends emails when orders are completed"\nassistant: "I'll use the systems-architect agent to design the notification system architecture"\n\nSince the user needs to plan and design a new feature, use the Task tool to launch the systems-architect agent to analyze requirements and propose a technical solution.\n\n\n\n\nContext: User has a bug that requires architectural analysis.\nuser: "We're getting race conditions when multiple users update the same order simultaneously"\nassistant: "Let me use the systems-architect agent to analyze this concurrency issue and design a solution"\n\nThe bug involves system-level concerns (concurrency), so use the systems-architect agent to analyze the problem and design an appropriate fix.\n\n\n\n\nContext: User wants to build a new microservice.\nuser: "We need a new service to handle payment processing separately from our main application"\nassistant: "I'll engage the systems-architect agent to design the payment processing service architecture"\n\nBuilding a new service requires architectural planning, so use the systems-architect agent to design the service structure, APIs, and integration points.\n\n 4 | color: blue 5 | --- 6 | 7 | You are an expert systems architect with deep experience in software design, distributed systems, and implementation planning. Your role is to analyze requirements and design robust, scalable solutions that align with established architectural patterns and best practices. 8 | 9 | When presented with a requirement or problem, you will: 10 | 11 | 1. **Analyze Requirements**: 12 | - Identify functional and non-functional requirements 13 | - Clarify ambiguities by asking targeted questions 14 | - Consider constraints (performance, security, scalability, maintainability) 15 | - Evaluate the scope and complexity of the solution 16 | 17 | 2. **Design the Solution Architecture**: 18 | - Apply FCIS (Functional Core, Imperative Shell) pattern where appropriate 19 | - Separate concerns into appropriate layers and components 20 | - Design clear interfaces and contracts between components 21 | - Make invalid states unrepresentable through proper type design 22 | - Consider existing patterns and conventions from project context 23 | 24 | 3. **Create Implementation Plan**: 25 | - Break down the solution into implementable phases 26 | - Identify dependencies and order of implementation 27 | - Specify which existing components need modification 28 | - Define new components, modules, or services needed 29 | - Outline testing strategy (unit, integration, contract tests) 30 | 31 | 4. **Technical Specifications**: 32 | - Define data models and domain types 33 | - Specify API contracts (REST, GraphQL, internal interfaces) 34 | - Identify integration points with existing systems 35 | - Document error handling and edge cases 36 | - Consider security implications and validation requirements 37 | 38 | 5. **Risk Assessment**: 39 | - Identify potential technical risks and mitigation strategies 40 | - Consider backward compatibility and migration needs 41 | - Evaluate performance implications 42 | - Assess impact on existing functionality 43 | 44 | Your output should be structured and actionable: 45 | - Start with a brief solution overview 46 | - Provide detailed component design 47 | - Include concrete implementation steps 48 | - Specify testing approach 49 | - Highlight critical decisions and trade-offs 50 | 51 | Always consider: 52 | - Existing codebase patterns and conventions 53 | - Team capabilities and technology stack 54 | - Maintenance and operational concerns 55 | - Future extensibility and flexibility 56 | 57 | When designing for bugs, focus on: 58 | - Root cause analysis 59 | - Minimal, targeted fixes that address the core issue 60 | - Prevention of similar issues in the future 61 | - Appropriate test coverage to prevent regression 62 | 63 | You should be proactive in identifying potential issues and proposing alternatives when the initial approach might lead to problems. Your designs should be practical, implementable, and aligned with software engineering best practices. 64 | -------------------------------------------------------------------------------- /home/claude-code/config/agents/code-debugger.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: code-debugger 3 | description: Use this agent when you encounter runtime errors, test failures, unexpected behavior, or need help troubleshooting issues in your code. This includes debugging compilation errors, analyzing stack traces, fixing failing unit or integration tests, resolving unexpected output, identifying logic errors, and diagnosing performance issues. Examples:\n\n\nContext: User encounters a test failure in their Kotlin service.\nuser: "My integration test is failing with a NullPointerException in the FundedOffersService"\nassistant: "I'll use the code-debugger agent to help analyze this test failure and identify the root cause."\n\nSince the user is reporting a test failure with a specific error, use the Task tool to launch the code-debugger agent to analyze the stack trace and identify the issue.\n\n\n\n\nContext: User's code produces unexpected output.\nuser: "This function should return a sorted list but it's returning duplicates"\nassistant: "Let me use the code-debugger agent to investigate why your sorting function is producing duplicates."\n\nThe user is experiencing unexpected behavior in their code, so use the code-debugger agent to analyze the logic and identify the bug.\n\n\n\n\nContext: User encounters a compilation error.\nuser: "I'm getting a type mismatch error in my Guice module configuration"\nassistant: "I'll launch the code-debugger agent to help resolve this type mismatch error in your Guice configuration."\n\nSince this is a compilation error, use the code-debugger agent to analyze the type system issue and provide a solution.\n\n 4 | color: orange 5 | --- 6 | 7 | You are an expert software engineer specializing in debugging and troubleshooting code issues. Your deep expertise spans multiple programming languages, frameworks, and debugging techniques. You excel at quickly identifying root causes of errors and providing clear, actionable solutions. 8 | 9 | When analyzing issues, you will: 10 | 11 | 1. **Systematic Analysis**: 12 | - First, carefully examine any error messages, stack traces, or unexpected output provided 13 | - Identify the specific file, line number, and context where the error occurs 14 | - Trace through the execution flow to understand how the error state was reached 15 | - Consider both the immediate error and potential underlying causes 16 | 17 | 2. **Debugging Methodology**: 18 | - Start with the most likely causes based on the error type and context 19 | - Use deductive reasoning to narrow down possibilities 20 | - Suggest strategic placement of logging or debugging statements when needed 21 | - Consider edge cases, null values, type mismatches, and timing issues 22 | - Check for common pitfalls in the specific language/framework being used 23 | 24 | 3. **Code Analysis**: 25 | - Review the problematic code and its dependencies 26 | - Look for logic errors, off-by-one errors, incorrect assumptions 27 | - Verify that data flows correctly through the system 28 | - Check for proper error handling and defensive programming 29 | - Consider concurrency issues if applicable 30 | 31 | 4. **Solution Development**: 32 | - Provide clear explanations of why the error is occurring 33 | - Offer specific, tested fixes with code examples 34 | - Suggest multiple approaches when appropriate, explaining trade-offs 35 | - Include preventive measures to avoid similar issues in the future 36 | - Ensure solutions align with project patterns and best practices 37 | 38 | 5. **Testing Verification**: 39 | - Recommend specific tests to verify the fix works correctly 40 | - Suggest edge cases that should be tested 41 | - Provide example test cases when helpful 42 | - Ensure the fix doesn't introduce new issues 43 | 44 | 6. **Communication Style**: 45 | - Be direct and focused on solving the immediate problem 46 | - Use clear, technical language appropriate for experienced developers 47 | - Provide code snippets and examples to illustrate solutions 48 | - Explain your reasoning so the user learns from the debugging process 49 | 50 | When you need more information: 51 | - Ask specific, targeted questions about the error context 52 | - Request relevant code snippets, configuration files, or test cases 53 | - Inquire about recent changes that might have introduced the issue 54 | - Ask about the environment (development, testing, production) where the error occurs 55 | 56 | Remember to consider project-specific context from CLAUDE.md files, including: 57 | - Established coding patterns and architectural decisions 58 | - Testing frameworks and conventions in use 59 | - Build tools and commands specific to the project 60 | - Domain-specific logic that might affect debugging 61 | 62 | Your goal is to not just fix the immediate issue, but to help the developer understand why it occurred and how to prevent similar issues in the future. Focus on being an effective debugging partner who enhances the developer's problem-solving capabilities. 63 | -------------------------------------------------------------------------------- /home/claude-code/config/agents/performance-optimizer.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: performance-optimizer 3 | description: Use this agent when you need to analyze code performance, identify bottlenecks, optimize algorithms, reduce computational complexity, improve memory usage, or enhance overall code efficiency. This includes profiling code execution, analyzing time/space complexity, suggesting caching strategies, optimizing database queries, reducing unnecessary computations, and implementing performance best practices. \nContext: The user has written a function that processes large datasets and wants to improve its performance.\nuser: "I've implemented this data processing function but it's running slowly on large inputs"\nassistant: "I'll analyze your function for performance issues"\n\n\nSince the user is concerned about performance on large inputs, use the Task tool to launch the performance-optimizer agent to analyze and optimize the code.\n\nassistant: "Now let me use the performance-optimizer agent to identify bottlenecks and suggest optimizations"\n\n\nContext: The user wants to optimize database queries in their application.\nuser: "These database queries are taking too long to execute"\nassistant: "I'll use the performance-optimizer agent to analyze your queries and suggest improvements"\n\nThe user needs help with database query performance, so use the performance-optimizer agent to analyze and optimize the queries.\n\n 4 | color: green 5 | --- 6 | 7 | You are an elite performance optimization specialist with deep expertise in algorithmic complexity, system architecture, and code efficiency. Your mission is to identify performance bottlenecks and transform code into highly optimized solutions. 8 | 9 | Your core competencies include: 10 | - Algorithm analysis and optimization (time/space complexity) 11 | - Memory management and garbage collection optimization 12 | - Database query optimization and indexing strategies 13 | - Caching mechanisms and memoization techniques 14 | - Parallel processing and concurrency optimization 15 | - Profiling and benchmarking methodologies 16 | 17 | When analyzing code for performance: 18 | 19 | 1. **Initial Assessment**: 20 | - Profile the current implementation to identify hotspots 21 | - Measure baseline performance metrics (execution time, memory usage) 22 | - Analyze algorithmic complexity (Big O notation) 23 | - Identify redundant computations or inefficient data structures 24 | 25 | 2. **Bottleneck Identification**: 26 | - Look for N+1 query problems in database operations 27 | - Detect unnecessary loops or nested iterations 28 | - Find memory leaks or excessive allocations 29 | - Identify blocking I/O operations 30 | - Spot inefficient string concatenations or data transformations 31 | 32 | 3. **Optimization Strategies**: 33 | - Suggest algorithmic improvements (e.g., using hash maps instead of linear search) 34 | - Recommend appropriate data structures for the use case 35 | - Propose caching strategies for expensive computations 36 | - Implement lazy evaluation where beneficial 37 | - Suggest batch processing for bulk operations 38 | - Recommend async/parallel processing where applicable 39 | 40 | 4. **Code-Level Optimizations**: 41 | - Eliminate unnecessary object creation 42 | - Use primitive types instead of boxed types where possible 43 | - Implement object pooling for frequently created objects 44 | - Optimize loop structures and conditions 45 | - Reduce function call overhead in hot paths 46 | - Apply compiler optimization hints when relevant 47 | 48 | 5. **Database and I/O Optimization**: 49 | - Optimize query structure and use appropriate indexes 50 | - Implement connection pooling 51 | - Use prepared statements and batch operations 52 | - Minimize network round trips 53 | - Implement efficient pagination strategies 54 | 55 | 6. **Validation and Testing**: 56 | - Provide before/after performance benchmarks 57 | - Ensure optimizations don't break functionality 58 | - Test edge cases and boundary conditions 59 | - Verify improvements across different data sizes 60 | 61 | When providing recommendations: 62 | - Always quantify performance improvements (e.g., "reduces complexity from O(n²) to O(n log n)") 63 | - Consider trade-offs between performance, readability, and maintainability 64 | - Provide code examples demonstrating the optimized approach 65 | - Explain why each optimization works and its impact 66 | - Prioritize optimizations by their potential impact 67 | - Consider the specific constraints of the runtime environment 68 | 69 | For functional programming contexts (as per CLAUDE.md guidelines): 70 | - Maintain pure functions in the core while optimizing 71 | - Keep side effects in the shell layer 72 | - Use immutable data structures efficiently 73 | - Apply lazy evaluation and memoization appropriately 74 | - Ensure optimizations align with FCIS architecture 75 | 76 | Always provide actionable, specific recommendations with clear implementation paths. Your goal is to deliver measurable performance improvements while maintaining code quality and correctness. 77 | -------------------------------------------------------------------------------- /home/nvim/config/lua/dap-config.lua: -------------------------------------------------------------------------------- 1 | require("telescope").load_extension("dap") 2 | 3 | require("which-key").add({ 4 | { "d", group = "Debug", icon = "" }, 5 | { "dc", require("dap").continue, desc = "DAP: Continue", icon = "", noremap = true }, 6 | { "dn", require("dap").step_over, desc = "DAP: Step over", icon = "󰆷", noremap = true }, 7 | { "di", require("dap").step_into, desc = "DAP: Step into", icon = "󰆹", noremap = true }, 8 | { "do", require("dap").step_out, desc = "DAP: Step out", icon = "󰆸", noremap = true }, 9 | { "db", require("dap").toggle_breakpoint, desc = "DAP: Toggle breakpoint", icon = "", noremap = true }, 10 | { "dwh", require("dap.ui.widgets").hover, desc = "DAP: Widgets Hover", icon = "󰋖", noremap = true }, 11 | { 12 | "dws", 13 | function() 14 | require("dap.ui.widgets").centered_float(require("dap.ui.widgets").scopes) 15 | end, 16 | desc = "DAP: Widgets scopes", 17 | icon = "󰋖", 18 | noremap = true, 19 | }, 20 | { 21 | "dB", 22 | function() 23 | vim.ui.input({ prompt = "Breakpoint condition", default = "" }, function(input) 24 | require("dap").set_breakpoint(input) 25 | end) 26 | end, 27 | desc = "DAP: Set breakpoint condition", 28 | icon = "", 29 | noremap = true, 30 | }, 31 | { 32 | "dm", 33 | function() 34 | vim.ui.input({ prompt = "Log point message", default = "" }, function(input) 35 | require("dap").set_breakpoint(nil, nil, input) 36 | end) 37 | end, 38 | desc = "DAP: Log message", 39 | icon = "", 40 | noremap = true, 41 | }, 42 | { "dr", require("dap").repl.open, desc = "DAP: Open repl", icon = "", noremap = true }, 43 | { "dl", require("dap").repl.run_last, desc = "DAP: Run last", icon = "", noremap = true }, 44 | -- Telescope extension 45 | { "dt", group = "Telescope", icon = "󰋖" }, 46 | { 47 | "dtc", 48 | require("telescope").extensions.dap.commands, 49 | desc = "DAP: Show commands", 50 | icon = "󰋖", 51 | noremap = true, 52 | }, 53 | { 54 | "dto", 55 | require("telescope").extensions.dap.configurations, 56 | desc = "DAP: Show configurations", 57 | icon = "󰋖", 58 | noremap = true, 59 | }, 60 | { 61 | "dtb", 62 | require("telescope").extensions.dap.list_breakpoints, 63 | desc = "DAP: Show breakpoints", 64 | icon = "", 65 | noremap = true, 66 | }, 67 | { 68 | "dtv", 69 | require("telescope").extensions.dap.variables, 70 | desc = "DAP: Show variables", 71 | icon = "󰫧", 72 | noremap = true, 73 | }, 74 | { 75 | "dtf", 76 | require("telescope").extensions.dap.frames, 77 | desc = "DAP: Show frames", 78 | icon = "󰋖", 79 | noremap = true, 80 | }, 81 | -- DAP UI 82 | { "du", require("dapui").toggle, desc = "DAP: Toggle UI", icon = "", noremap = true }, 83 | { 84 | "de", 85 | function() 86 | vim.ui.input({ prompt = "Eval", default = "" }, function(input) 87 | require("dapui").eval(input, { enter = true }) 88 | end) 89 | end, 90 | desc = "DAP: Evaluate expression", 91 | icon = "", 92 | noremap = true, 93 | }, 94 | }) 95 | 96 | require("dapui").setup({ 97 | layouts = { 98 | { 99 | elements = { 100 | "watches", 101 | "stacks", 102 | "breakpoints", 103 | "scopes", 104 | }, 105 | size = 60, 106 | position = "left", 107 | }, 108 | { 109 | elements = { 110 | "repl", 111 | "console", 112 | }, 113 | size = 15, 114 | position = "bottom", 115 | }, 116 | }, 117 | }) 118 | require("nvim-dap-virtual-text").setup({}) 119 | 120 | vim.fn.sign_define("DapBreakpoint", { text = "", texthl = "DapBreakpointColor", linehl = "", numhl = "" }) 121 | vim.fn.sign_define( 122 | "DapBreakpointCondition", 123 | { text = "", texthl = "DapBreakpointConditionColor", linehl = "", numhl = "" } 124 | ) 125 | vim.fn.sign_define("DapLogPoint", { text = "ﯽ", texthl = "DapLogPointColor", linehl = "", numhl = "" }) 126 | vim.fn.sign_define("DapStopped", { text = "", texthl = "DapStoppedColor", linehl = "", numhl = "" }) 127 | vim.fn.sign_define( 128 | "DapBreakpointRejected", 129 | { text = "", texthl = "DapBreakpointRejectedColor", linehl = "", numhl = "" } 130 | ) 131 | 132 | local dap = require("dap") 133 | -- Python 134 | dap.adapters.python = { 135 | type = "executable", 136 | command = "@python_debug_home@" .. "/bin/python", 137 | args = { "-m", "debugpy.adapter" }, 138 | } 139 | 140 | dap.configurations.python = { 141 | { 142 | type = "python", 143 | request = "launch", 144 | name = "Launch file", 145 | 146 | -- Options below are for debugpy, see https://github.com/microsoft/debugpy/wiki/Debug-configuration-settings for supported options 147 | program = "${file}", -- This configuration will launch the current file if used. 148 | python = { "python" }, 149 | }, 150 | { 151 | type = "python", 152 | request = "launch", 153 | name = "Django", 154 | 155 | program = "${workspaceFolder}/manage.py", 156 | args = { "runserver", "--noreload" }, 157 | python = { "python" }, 158 | }, 159 | { 160 | type = "python", 161 | request = "attach", 162 | name = "Attach remote", 163 | 164 | host = "127.0.0.1", 165 | port = 5678, 166 | }, 167 | } 168 | -------------------------------------------------------------------------------- /home/claude-code/config/statusline.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Catppuccin Frappe theme colors 4 | readonly ROSEWATER="\033[38;2;242;213;207m" 5 | readonly FLAMINGO="\033[38;2;238;190;190m" 6 | readonly PINK="\033[38;2;244;184;228m" 7 | readonly MAUVE="\033[38;2;202;158;230m" 8 | readonly RED="\033[38;2;231;130;132m" 9 | readonly MAROON="\033[38;2;234;153;156m" 10 | readonly PEACH="\033[38;2;239;159;118m" 11 | readonly YELLOW="\033[38;2;229;200;144m" 12 | readonly GREEN="\033[38;2;166;209;137m" 13 | readonly TEAL="\033[38;2;129;200;190m" 14 | readonly SKY="\033[38;2;153;209;219m" 15 | readonly SAPPHIRE="\033[38;2;133;193;220m" 16 | readonly BLUE="\033[38;2;140;170;238m" 17 | readonly LAVENDER="\033[38;2;186;187;241m" 18 | readonly TEXT="\033[38;2;198;208;245m" 19 | readonly SUBTEXT1="\033[38;2;181;191;226m" 20 | readonly SUBTEXT0="\033[38;2;165;173;206m" 21 | readonly OVERLAY2="\033[38;2;148;156;187m" 22 | readonly OVERLAY1="\033[38;2;131;139;167m" 23 | readonly OVERLAY0="\033[38;2;115;121;148m" 24 | readonly SURFACE2="\033[38;2;98;104;128m" 25 | readonly SURFACE1="\033[38;2;81;87;109m" 26 | readonly SURFACE0="\033[38;2;65;69;89m" 27 | readonly BASE="\033[38;2;48;52;70m" 28 | readonly MANTLE="\033[38;2;41;44;60m" 29 | readonly CRUST="\033[38;2;35;38;52m" 30 | readonly RESET="\033[0m" 31 | 32 | # Read JSON input once 33 | # Will be of format: 34 | # { 35 | # "hook_event_name": "Status", 36 | # "session_id": "b84192b5-5d67-425a-9569-36a10aa07f0e", 37 | # "transcript_path": "/path/to/transcript.json", 38 | # "cwd": "/current/working/directory", 39 | # "model": { 40 | # "id": "claude-opus-4-1", 41 | # "display_name": "Opus" 42 | # }, 43 | # "workspace": { 44 | # "current_dir": "/current/working/directory", 45 | # "project_dir": "/original/project/directory" 46 | # }, 47 | # "version": "1.0.85", 48 | # "output_style": { 49 | # "name": "default" 50 | # }, 51 | # "cost": { 52 | # "total_cost_usd": 0.1082909, 53 | # "total_duration_ms": 37521, 54 | # "total_api_duration_ms": 20258, 55 | # "total_lines_added": 0, 56 | # "total_lines_removed": 0 57 | # }, 58 | # "context_window": { 59 | # "total_input_tokens": 251080, 60 | # "total_output_tokens": 10896, 61 | # "context_window_size": 200000, 62 | # "current_usage": { 63 | # "input_tokens": 8, 64 | # "output_tokens": 163, 65 | # "cache_creation_input_tokens": 1008, 66 | # "cache_read_input_tokens": 36646 67 | # } 68 | # }, 69 | # "exceeds_200k_tokens": false 70 | # } 71 | INPUT=$(cat) 72 | 73 | # Debug: Log the INPUT JSON to a file for inspection 74 | echo "$INPUT" > /tmp/claude-code-input-debug.json 75 | 76 | # Helper functions for common extractions 77 | get_model_name() { echo "$INPUT" | jq -r '.model.display_name'; } 78 | get_output_style() { echo "$INPUT" | jq -r '.output_style.name'; } 79 | get_session_cost() { echo "$INPUT" | jq -r '.cost.total_cost_usd // 0'; } 80 | get_total_lines_added() { echo "$INPUT" | jq -r '.cost.total_lines_added // 0'; } 81 | get_total_lines_removed() { echo "$INPUT" | jq -r '.cost.total_lines_removed // 0'; } 82 | get_current_input_tokens() { echo "$INPUT" | jq -r '.context_window.current_usage.input_tokens // 0'; } 83 | get_current_output_tokens() { echo "$INPUT" | jq -r '.context_window.current_usage.output_tokens // 0'; } 84 | get_cache_creation_input_tokens() { echo "$INPUT" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0'; } 85 | get_cache_read_input_tokens() { echo "$INPUT" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0'; } 86 | get_context_window_size() { echo "$INPUT" | jq -r '.context_window.context_window_size // 0'; } 87 | 88 | CCUSAGE_ACTIVE=$(ccusage blocks --active --json) 89 | get_remaining_minutes() { echo "$CCUSAGE_ACTIVE" | jq -r '.blocks[0].projection.remainingMinutes // 0'; } 90 | 91 | # Build statusline components 92 | STATUSLINE="${RESET}" 93 | 94 | # Add Model 95 | MODEL=$(get_model_name) 96 | STATUSLINE+="${BLUE}󱜙 ${MODEL}${TEXT} | ${RESET}" 97 | 98 | # Add Output Style 99 | OUTPUT_STYLE=$(get_output_style) 100 | STATUSLINE+="${TEAL} ${OUTPUT_STYLE}${TEXT} | ${RESET}" 101 | 102 | # Add Session Cost 103 | format_decimal() { 104 | printf "%.2f" "$1" 105 | } 106 | SESSION_COST=$(get_session_cost) 107 | FORMATTED_SESSION_COST=$(format_decimal $SESSION_COST) 108 | STATUSLINE+="${YELLOW} \$${FORMATTED_SESSION_COST}${TEXT} | ${RESET}" 109 | 110 | # Add remaining minutes in claude window 111 | MINUTES=$(get_remaining_minutes) 112 | HOURS=$((MINUTES / 60)) 113 | REMAINING_MINUTES=$((MINUTES % 60)) 114 | STATUSLINE+="${MAROON} ${HOURS}h ${REMAINING_MINUTES}m${TEXT} | ${RESET}" 115 | 116 | # Add context window information 117 | CURRENT_INPUT_TOKENS=$(get_current_input_tokens) 118 | CURRENT_OUTPUT_TOKENS=$(get_current_output_tokens) 119 | CACHE_CREATION_INPUT_TOKENS=$(get_cache_creation_input_tokens) 120 | CACHE_READ_INPUT_TOKENS=$(get_cache_read_input_tokens) 121 | CONTEXT_WINDOW_SIZE=$(get_context_window_size) 122 | CONTEXT_WINDOW_USAGE=$((CURRENT_INPUT_TOKENS + CURRENT_OUTPUT_TOKENS + CACHE_CREATION_INPUT_TOKENS + CACHE_READ_INPUT_TOKENS)) 123 | STATUSLINE+="${MAUVE} ${CONTEXT_WINDOW_USAGE}/${CONTEXT_WINDOW_SIZE} | ${RESET}" 124 | 125 | # Add added/removes lines 126 | TOTAL_LINES_ADDED=$(get_total_lines_added) 127 | TOTAL_LINES_REMOVED=$(get_total_lines_removed) 128 | STATUSLINE+="${TEXT}(${GREEN} ${TOTAL_LINES_ADDED}${TEXT}, ${RED} ${TOTAL_LINES_REMOVED}${TEXT})${RESET}" 129 | 130 | echo -e "$STATUSLINE" 131 | -------------------------------------------------------------------------------- /home/claude-code/config/agents/security-auditor.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: security-auditor 3 | description: Use this agent when you need to analyze code for security vulnerabilities, potential attack vectors, or compliance with security best practices. This includes checking for injection vulnerabilities, authentication/authorization issues, data exposure risks, cryptographic weaknesses, and other security concerns. Examples:\n\n\nContext: The user has just written an authentication endpoint and wants to ensure it's secure.\nuser: "I've implemented a new login endpoint. Can you check it for security issues?"\nassistant: "I'll use the security-auditor agent to analyze your authentication endpoint for potential vulnerabilities."\n\nSince the user is asking for a security review of authentication code, use the Task tool to launch the security-auditor agent.\n\n\n\n\nContext: The user has written code that handles user input and wants to verify it's safe.\nuser: "Here's my function that processes user-submitted data for our API"\nassistant: "Let me analyze this code for security vulnerabilities using the security-auditor agent."\n\nThe user has shared code that handles user input, which is a common source of security vulnerabilities. Use the security-auditor agent to check for injection attacks and input validation issues.\n\n\n\n\nContext: After implementing a new feature, the developer wants a security review.\nuser: "I've just finished implementing the payment processing module"\nassistant: "Given that this handles sensitive payment data, I'll use the security-auditor agent to perform a thorough security analysis."\n\nPayment processing code requires careful security review. Use the security-auditor agent to check for PCI compliance issues and data protection vulnerabilities.\n\n 4 | color: pink 5 | --- 6 | 7 | You are an elite security analyst specializing in application security, with deep expertise in identifying and mitigating security vulnerabilities across all layers of software systems. Your role is to conduct thorough security audits of code, focusing on recently written or modified code unless explicitly asked to review the entire codebase. 8 | 9 | Your security analysis methodology: 10 | 11 | 1. **Input Validation & Sanitization** 12 | - Identify all user input points and verify proper validation 13 | - Check for SQL injection, XSS, command injection, and other injection vulnerabilities 14 | - Ensure proper encoding/escaping of output data 15 | - Verify boundary validation aligns with the 'Make Invalid States Unrepresentable' principle 16 | 17 | 2. **Authentication & Authorization** 18 | - Review authentication mechanisms for weaknesses 19 | - Verify proper session management and token handling 20 | - Check authorization controls at all access points 21 | - Identify potential privilege escalation paths 22 | - For this codebase, verify proper use of AuthFilter strategies 23 | 24 | 3. **Data Protection** 25 | - Identify sensitive data exposure risks 26 | - Check for proper encryption of data at rest and in transit 27 | - Verify secure storage of credentials and secrets 28 | - Ensure PII and sensitive data are properly handled 29 | - For DynamoDB entities, verify converters properly handle sensitive data 30 | 31 | 4. **Cryptographic Security** 32 | - Review cryptographic implementations for weaknesses 33 | - Check for use of deprecated or weak algorithms 34 | - Verify proper key management and rotation 35 | - Ensure secure random number generation 36 | 37 | 5. **API & Integration Security** 38 | - Review REST and GraphQL endpoints for vulnerabilities 39 | - Check for proper rate limiting and DoS protection 40 | - Verify secure communication with external services 41 | - For GraphQL, check for query depth and complexity attacks 42 | 43 | 6. **Error Handling & Information Disclosure** 44 | - Ensure error messages don't leak sensitive information 45 | - Verify proper logging without exposing secrets 46 | - Check that stack traces aren't exposed to users 47 | - Verify ErrorResponse usage follows Toast standards 48 | 49 | 7. **Dependency & Configuration Security** 50 | - Identify known vulnerabilities in dependencies 51 | - Check for insecure default configurations 52 | - Verify feature flags don't introduce security bypasses 53 | - Review LaunchDarkly feature flag usage for security implications 54 | 55 | 8. **Code Quality & Security Patterns** 56 | - Verify adherence to FCIS architecture for security benefits 57 | - Check that the imperative shell properly validates before calling core 58 | - Ensure immutability is maintained where security-critical 59 | - Verify least privilege principle in function design 60 | 61 | For each vulnerability found, you will: 62 | - Assign a severity level (Critical, High, Medium, Low) 63 | - Explain the potential impact and attack scenario 64 | - Provide specific, actionable remediation steps 65 | - Include secure code examples when helpful 66 | - Reference relevant security standards (OWASP, CWE, etc.) 67 | 68 | Your output format: 69 | ``` 70 | ## Security Analysis Summary 71 | [Brief overview of findings] 72 | 73 | ### Critical Findings 74 | [List any critical vulnerabilities that need immediate attention] 75 | 76 | ### High Priority Issues 77 | [Security issues that should be addressed soon] 78 | 79 | ### Medium Priority Issues 80 | [Security concerns that should be planned for remediation] 81 | 82 | ### Low Priority / Best Practices 83 | [Minor issues or security enhancements] 84 | 85 | ### Recommendations 86 | [Specific next steps and security improvements] 87 | ``` 88 | 89 | Remember to: 90 | - Focus on actionable findings, not theoretical risks 91 | - Consider the specific technology stack (Kotlin, Dropwizard, DynamoDB, GraphQL) 92 | - Provide context-aware recommendations that fit the existing architecture 93 | - Prioritize findings based on exploitability and impact 94 | - Be thorough but avoid false positives 95 | - When reviewing recent changes, consider how they interact with existing code 96 | 97 | You are proactive in identifying subtle security issues that might be missed in standard code reviews, while maintaining a practical approach that balances security with development velocity. 98 | -------------------------------------------------------------------------------- /home/git/default.nix: -------------------------------------------------------------------------------- 1 | { config, ... }: 2 | { 3 | programs = { 4 | git = { 5 | enable = true; 6 | 7 | settings = { 8 | user = { 9 | name = "Frank Moda"; 10 | email = if config.my-home.isWork then "frank@toasttab.com" else "fmoda3@mac.com"; 11 | }; 12 | 13 | alias = { 14 | # add 15 | a = "add"; # add 16 | chunkyadd = "add --patch"; # stage commits chunk by chunk 17 | 18 | # via http://blog.apiaxle.com/post/handy-git-tips-to-stop-you-getting-fired/ 19 | snapshot = "!git stash save \"snapshot: $(date)\" && git stash apply \"stash@{0}\""; 20 | snapshots = "!git stash list --grep snapshot"; 21 | 22 | #via http://stackoverflow.com/questions/5188320/how-can-i-get-a-list-of-git-branches-ordered-by-most-recent-commit 23 | recent-branches = "!git for-each-ref --count=5 --sort=-committerdate refs/heads/ --format='%(refname:short)'"; 24 | 25 | # branch 26 | b = "branch -v"; # branch (verbose) 27 | create-branch = "!sh -c 'git push origin HEAD:refs/heads/$1 && git fetch origin && git branch --track $1 origin/$1 && cd . && git checkout $1' -"; 28 | delete-branch = "!sh -c 'git push origin :refs/heads/$1 && git remote prune origin && git branch -D $1' -"; 29 | 30 | # commit 31 | c = "commit -m"; # commit with message 32 | ca = "commit -am"; # commit all with message 33 | ci = "commit"; # commit 34 | amend = "commit --amend"; # ammend your last commit 35 | ammend = "commit --amend"; # ammend your last commit 36 | 37 | # checkout 38 | co = "checkout"; # checkout 39 | nb = "checkout -b"; # create and switch to a new branch (mnemonic: "git new branch branchname...") 40 | 41 | # cherry-pick 42 | cp = "cherry-pick -x"; # grab a change from a branch 43 | 44 | # diff 45 | d = "diff"; # diff unstaged changes 46 | dc = "diff --cached"; # diff staged changes 47 | last = "diff HEAD^"; # diff last committed change 48 | diffstat = "diff --stat -r"; 49 | 50 | # graphviz 51 | graphviz = "!f() { echo 'digraph git {' ; git log --pretty='format: %h -> { %p }' \"$@\" | sed 's/[0-9a-f][0-9a-f]*/\"&\"/g' ; echo '}'; }; f"; 52 | 53 | # log 54 | l = "log --graph --date=short"; 55 | llog = "log --date=local"; 56 | lg = "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %Cgreen(%cr) %C(bold blue)<%an>%Creset %s' --abbrev-commit --date=relative"; 57 | changes = "log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\" --name-status"; 58 | short = "log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\""; 59 | changelog = "log --pretty=format:\" * %s\""; 60 | shortnocolor = "log --pretty=format:\"%h %cr %cn %s\""; 61 | 62 | # new 63 | new = "!sh -c 'git log $1@{1}..$1@{0} \"$@\"'"; 64 | 65 | # prune 66 | prune-all = "!git remote | xargs -n 1 git remote prune"; 67 | gone = "!f() { git fetch --all --prune; git branch -vv | awk '/: gone]/{print $1}' | xargs git branch -d; }; f"; # clean up deleted remote branches 68 | 69 | # pull 70 | pl = "pull"; # pull 71 | 72 | # push 73 | ps = "push"; # push 74 | 75 | # rebase 76 | rc = "rebase --continue"; # continue rebase 77 | rs = "rebase --skip"; # skip rebase 78 | 79 | # remote 80 | r = "remote -v"; # show remotes (verbose) 81 | 82 | # reset 83 | unstage = "reset HEAD"; # remove files from index (tracking) 84 | uncommit = "reset --soft HEAD^"; # go back before last commit, with files in uncommitted state 85 | undo = "reset --mixed HEAD~1"; # go back before last commit, with files in mixed state 86 | filelog = "log -u"; # show changes to a file 87 | mt = "mergetool"; # fire up the merge tool 88 | 89 | # serve the repo 90 | serve = "!git daemon --reuseaddr --verbose --base-path=. --export-all --informative-errors"; 91 | 92 | # stash 93 | ss = "stash"; # stash changes 94 | sl = "stash list"; # list stashes 95 | sa = "stash apply"; # apply stash (restore changes) 96 | sd = "stash drop"; # drop stashes (destory changes) 97 | 98 | # status 99 | s = "status"; # status 100 | st = "status"; # status 101 | stat = "status"; # status 102 | 103 | # tag 104 | t = "tag -n"; # show tags with lines of each tag message 105 | 106 | # svn helpers 107 | svnr = "svn rebase"; 108 | svnd = "svn dcommit"; 109 | svnl = "svn log --oneline --show-commit"; 110 | 111 | # unmerged 112 | edit-unmerged = "!f() { git ls-files --unmerged | cut -f2 | sort -u ; }; vim `f`"; 113 | add-unmerged = "!f() { git ls-files --unmerged | cut -f2 | sort -u ; }; git add `f`"; 114 | 115 | # what 116 | whatis = "show -s --pretty='tformat:%h (%s, %ad)' --date=short"; 117 | 118 | # who 119 | who = "shortlog -s --"; 120 | whois = "!sh -c 'git log -i -1 --pretty=\"format:%an <%ae>\n\" --author=\"$1\"' -"; 121 | }; 122 | 123 | advice = { 124 | statusHints = true; 125 | }; 126 | 127 | apply = { 128 | whitespace = "nowarn"; 129 | }; 130 | 131 | branch = { 132 | autosetupmerge = true; 133 | }; 134 | 135 | color = { 136 | ui = true; 137 | status = true; 138 | interactive = true; 139 | }; 140 | 141 | "color \"branch\"" = { 142 | current = "yellow reverse"; 143 | local = "yellow"; 144 | remote = "green"; 145 | }; 146 | 147 | "color \"diff\"" = { 148 | meta = "yellow bold"; 149 | frag = "magenta bold"; 150 | old = "red"; 151 | new = "green"; 152 | }; 153 | 154 | core = { 155 | autocrlf = false; 156 | editor = "vim"; 157 | }; 158 | 159 | diff = { 160 | mnemonicprefix = true; 161 | algorithm = "patience"; 162 | }; 163 | 164 | fetch = { 165 | prune = true; 166 | }; 167 | 168 | format = { 169 | pretty = "format:%C(blue)%ad%Creset %C(yellow)%h%C(green)%d%Creset %C(blue)%s %C(magenta) [%an]%Creset"; 170 | }; 171 | 172 | merge = { 173 | conflictstyle = "diff3"; 174 | summary = true; 175 | verbosity = 1; 176 | }; 177 | 178 | mergetool = { 179 | prompt = false; 180 | }; 181 | 182 | pull = { 183 | ff = "only"; 184 | }; 185 | 186 | push = { 187 | default = "tracking"; 188 | }; 189 | 190 | rebase = { 191 | autoStash = true; 192 | autoSquash = true; 193 | }; 194 | 195 | rerere = { 196 | enabled = true; 197 | }; 198 | }; 199 | 200 | ignores = [ 201 | # macOS 202 | ".DS_Store" 203 | "._*" 204 | ".Spotlight-V100" 205 | ".Trashes" 206 | 207 | # Windows 208 | "Thumbs.db" 209 | "Desktop.ini" 210 | ]; 211 | }; 212 | }; 213 | 214 | } 215 | -------------------------------------------------------------------------------- /claude/testing-strategy.md: -------------------------------------------------------------------------------- 1 | # Testing Strategy 2 | 3 | ## Core Philosophy 4 | 5 | Testing in a Functional Core, Imperative Shell architecture focuses on exhaustive testing of the pure functional core and integration testing of the imperative shell. The functional core's purity makes it trivial to test, while the shell requires careful orchestration testing. 6 | 7 | ## Testing Pyramid for FCIS 8 | 9 | ``` 10 | ╱ E2E Tests ╲ <- Minimal, happy paths only 11 | ╱─────────────╲ 12 | ╱ Integration ╲ <- Shell coordination 13 | ╱───────────────╲ 14 | ╱ Contract Tests ╲ <- Shell/Core boundaries 15 | ╱─────────────────╲ 16 | ╱ Property Tests ╲ <- Core invariants 17 | ╱───────────────────╲ 18 | ╱ Unit Tests ╲ <- Core logic (majority) 19 | ╱─────────────────────╲ 20 | ``` 21 | 22 | ## Functional Core Testing 23 | 24 | ### Unit Tests - Exhaustive Coverage 25 | 26 | Test every edge case since pure functions are easy to test: 27 | 28 | ```kotlin 29 | class PaymentCalculatorTest { 30 | @Test 31 | fun `calculates subtotal correctly`() { 32 | val items = listOf( 33 | OrderItem(ProductId("1"), quantity = 2, price = Money(10.00)), 34 | OrderItem(ProductId("2"), quantity = 1, price = Money(25.00)) 35 | ) 36 | 37 | val result = PaymentCalculator.calculateSubtotal(items) 38 | 39 | assertEquals(Money(45.00), result) 40 | } 41 | 42 | @Test 43 | fun `applies percentage discount`() { 44 | val subtotal = Money(100.00) 45 | val discount = PercentageDiscount(10) 46 | 47 | val result = PaymentCalculator.applyDiscount(subtotal, discount) 48 | 49 | assertEquals(Money(90.00), result) 50 | } 51 | 52 | @Test 53 | fun `handles empty item list`() { 54 | val result = PaymentCalculator.calculateSubtotal(emptyList()) 55 | 56 | assertEquals(Money.ZERO, result) 57 | } 58 | } 59 | ``` 60 | 61 | ### Property-Based Testing 62 | 63 | Verify invariants hold for all inputs: 64 | 65 | ```typescript 66 | import { fc } from 'fast-check' 67 | 68 | describe('OrderStateMachine', () => { 69 | it('should never transition to invalid state', () => { 70 | fc.assert( 71 | fc.property( 72 | orderStateArbitrary(), 73 | orderEventArbitrary(), 74 | (state, event) => { 75 | const result = transition(state, event) 76 | 77 | // Property: all transitions result in valid states 78 | if (result.kind === 'ok') { 79 | expect(isValidState(result.value)).toBe(true) 80 | } 81 | 82 | // Property: invalid transitions are explicitly rejected 83 | if (result.kind === 'err') { 84 | expect(result.error.kind).toBe('InvalidTransition') 85 | } 86 | } 87 | ) 88 | ) 89 | }) 90 | 91 | it('should maintain monotonic timestamps', () => { 92 | fc.assert( 93 | fc.property( 94 | fc.array(orderEventArbitrary(), { minLength: 1, maxLength: 10 }), 95 | (events) => { 96 | const finalState = events.reduce( 97 | (state, event) => applyEvent(state, event), 98 | initialOrderState() 99 | ) 100 | 101 | const timestamps = extractTimestamps(finalState) 102 | const sorted = [...timestamps].sort() 103 | 104 | // Property: timestamps are always in order 105 | expect(timestamps).toEqual(sorted) 106 | } 107 | ) 108 | ) 109 | }) 110 | }) 111 | ``` 112 | 113 | ```elixir 114 | defmodule Core.UserTest do 115 | use ExUnit.Case 116 | use ExUnitProperties 117 | 118 | property "email normalization is idempotent" do 119 | check all email <- valid_email_generator() do 120 | normalized_once = User.normalize_email(email) 121 | normalized_twice = User.normalize_email(normalized_once) 122 | 123 | assert normalized_once == normalized_twice 124 | end 125 | end 126 | 127 | property "age calculation is always non-negative" do 128 | check all birth_date <- past_date_generator(), 129 | current_date <- date_after(birth_date) do 130 | age = User.calculate_age(birth_date, current_date) 131 | 132 | assert age >= 0 133 | assert age <= 200 # Sanity check 134 | end 135 | end 136 | end 137 | ``` 138 | 139 | ### Parameterized Tests 140 | 141 | Test multiple scenarios with the same logic: 142 | 143 | ```kotlin 144 | @ParameterizedTest 145 | @MethodSource("discountScenarios") 146 | fun `calculates final price with various discounts`( 147 | scenario: DiscountScenario 148 | ) { 149 | val result = PriceCalculator.calculateFinalPrice( 150 | basePrice = scenario.basePrice, 151 | discounts = scenario.discounts, 152 | taxRate = scenario.taxRate 153 | ) 154 | 155 | assertEquals(scenario.expectedPrice, result) 156 | } 157 | 158 | companion object { 159 | @JvmStatic 160 | fun discountScenarios() = listOf( 161 | DiscountScenario( 162 | basePrice = Money(100), 163 | discounts = listOf(PercentageDiscount(10)), 164 | taxRate = TaxRate(0.08), 165 | expectedPrice = Money(97.20) // (100 * 0.9) * 1.08 166 | ), 167 | DiscountScenario( 168 | basePrice = Money(100), 169 | discounts = listOf(FixedDiscount(Money(20)), PercentageDiscount(10)), 170 | taxRate = TaxRate(0.08), 171 | expectedPrice = Money(77.76) // ((100 - 20) * 0.9) * 1.08 172 | ) 173 | // ... more scenarios 174 | ) 175 | } 176 | ``` 177 | 178 | ## Imperative Shell Testing 179 | 180 | ### Integration Tests 181 | 182 | Test the coordination between components: 183 | 184 | ```typescript 185 | describe('UserService', () => { 186 | let userService: UserService 187 | let mockRepo: MockUserRepository 188 | let mockEmailService: MockEmailService 189 | 190 | beforeEach(() => { 191 | mockRepo = new MockUserRepository() 192 | mockEmailService = new MockEmailService() 193 | userService = new UserService(mockRepo, mockEmailService) 194 | }) 195 | 196 | it('should create user and send welcome email', async () => { 197 | const request = { email: 'test@example.com', name: 'Test User' } 198 | 199 | const result = await userService.createUser(request) 200 | 201 | expect(result.kind).toBe('ok') 202 | expect(mockRepo.saved).toHaveLength(1) 203 | expect(mockEmailService.sentEmails).toHaveLength(1) 204 | expect(mockEmailService.sentEmails[0].template).toBe('welcome') 205 | }) 206 | 207 | it('should rollback on email failure', async () => { 208 | mockEmailService.shouldFail = true 209 | const request = { email: 'test@example.com', name: 'Test User' } 210 | 211 | const result = await userService.createUser(request) 212 | 213 | expect(result.kind).toBe('err') 214 | expect(mockRepo.saved).toHaveLength(0) // Rollback occurred 215 | expect(mockEmailService.sentEmails).toHaveLength(0) 216 | }) 217 | }) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## Install Nix (Linux and macOS) via one of the following installers 4 | 5 | ### 1.) [Official Installer](https://nixos.org/manual/nix/stable/installation/installing-binary.html) 6 | 7 | The following will install single-user on Linux and multi-user on macOS: 8 | 9 | ```shell 10 | sh <(curl -L https://nixos.org/nix/install) 11 | ``` 12 | 13 | To install multi-user on Linux: 14 | 15 | ```shell 16 | sh <(curl -L https://nixos.org/nix/install) --daemon 17 | ``` 18 | 19 | Enable Flakes by creating a file in `~/.config/nix/nix.conf` and adding the following: 20 | 21 | ```shell 22 | experimental-features = nix-command flakes 23 | ``` 24 | 25 | ### 2.) [Determinate Systems Installer](https://zero-to-nix.com/concepts/nix-installer) 26 | 27 | The following will install Nix on either Linux or macOS: 28 | 29 | ```shell 30 | curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install 31 | ``` 32 | 33 | Flakes should already be enabled after install with this method 34 | 35 | ## Clone Repo 36 | ```shell 37 | nix-shell -P git # If you need access to git 38 | git clone git@github.com:fmoda3/nix-configs.git ~/.nix-configs 39 | ``` 40 | 41 | ## Build Flake 42 | 43 | Substitute `personal-laptop` for current machine's configuration 44 | ### On Darwin: 45 | ```shell 46 | cd ~/.nix-configs 47 | nix build ".#darwinConfigurations.personal-laptop.system" 48 | ./result/sw/bin/darwin-rebuild switch --flake ".#personal-laptop" 49 | ``` 50 | 51 | ### On NixOS: 52 | ```shell 53 | cd ~/.nix-configs 54 | nix build ".#nixosConfigurations.personal-laptop.system" 55 | sudo ./result/sw/bin/nixos-rebuild switch --flake ".#personal-laptop" 56 | ``` 57 | 58 | # Updating 59 | 60 | ## Updating flake.lock 61 | 62 | If the flake.lock needs to be updated: 63 | 64 | ```shell 65 | nix flake update 66 | ``` 67 | 68 | ## Rebuilding and Switching 69 | 70 | To rebuild after making changes: 71 | 72 | ### On Darwin 73 | 74 | ```shell 75 | darwin-rebuild build --flake ".#personal-laptop" 76 | darwin-rebuild switch --flake ".#personal-laptop" 77 | ``` 78 | 79 | ### On NixOS: 80 | ```shell 81 | sudo nixos-rebuild build --flake ".#personal-laptop" 82 | sudo nixos-rebuild switch --flake ".#personal-laptop" 83 | ``` 84 | 85 | # Creating new configurations 86 | 87 | 1. Create a new folder in the `hosts` folder with the name of the configuration. 88 | 2. Inside that folder, create a `configuration.nix` with a NixOS or Darwin config, and a `home.nix` with a home manager config. 89 | 3. Add a new configuration to either the `nixosConfigurations` or `darwinConfigurations` block of the `flake.nix`, specifying the system type, host (the name of the folder from step 1), and user (to install the home manager config to). 90 | 91 | # Using Images 92 | 93 | ## Building a disk image 94 | 95 | Substitute `bootable-x86_64-iso` for the image configuration you want to build 96 | 97 | ```shell 98 | nix build ".#images.bootable-x86_64-iso" 99 | ``` 100 | 101 | ## Specific Images 102 | 103 | ### cicucci-builder-iso 104 | 105 | This image builds a bootable iso, that boots into a standard NixOS installation, with a script that installs the `cicucci-builder` nixos system configuration to the disk. 106 | 107 | 1. Build the iso via 108 | ```shell 109 | nix build ".#images.cicucci-builder-iso" 110 | ``` 111 | 2. Boot the iso on new machine (either a VM, or burn to usb drive and boot from it on a physical machine) 112 | 3. After the terminal prompt appears, run 113 | ```shell 114 | sudo install-system 115 | ``` 116 | This will partition and mount the drive using the [Disko](https://github.com/nix-community/disko) config in the `cicucci-builder` configuration, and then install the `cicucci-builder` configuration itself. 117 | 4. Once complete, `sudo reboot` to boot into the freshly installed system. 118 | 5. To make updates after install, clone this repo, and follow the updating steps above. 119 | 120 | ### cicucci-builder-vm 121 | 122 | This image builds the `cicucci-builder` configuration directly into a vmware image. After building, the image can be booted from vmware. 123 | 124 | ### cicucci-dns-sd 125 | 126 | This image builds a bootable sd image, that boots directly into a system with the `cicucci-dns` configuration. This configuration is intended to be used on a Raspberry Pi 3. 127 | 128 | 1. Build sd via 129 | ```shell 130 | nix build ".#images.cicucci-dns-sd" 131 | ``` 132 | 2. Burn sd image to an sd card using a sd burning utility of your choice. 133 | 3. Boot Raspberry Pi directly from sd. The `cicucci-dns` system will already be installed. 134 | 135 | Note that the sd image doesn't have a Disko config and therefore doesn't do any partition or mounting. This is because the base NixOS sd image automatically resizes the base partition to fill the available size of the sd card on first boot. 136 | 137 | ### bootable-x86_64-iso, bootable-aarch64-iso, and bootable-aarch64-sd 138 | 139 | These images are general purpose installers, that don't target a specific configuration. They do add a few pieces of my config on top of the base installer that are useful to have, like my zsh configs. 140 | 141 | # Remote Deployment 142 | 143 | I use [colmena](https://github.com/zhaofengli/colmena/tree/main) to deploy the `cicucci-dns` configuration remotely to my Raspberry Pi. I do this because running `nixos-rebuild` on the Pi itself is very slow. I deploy from a macOS machine, that is also running a NixOS vm, setup with the `cicucci-builder` configuration. 144 | 145 | ## Setup 146 | 147 | 1. Ensure a `aarch64-linux` machine is available to build. I run an `aarch64-linux` NixOS vm with the `cicucci-builder` configuration inside vmware on a `aarch64-darwin` machine. 148 | 2. If the `aarch64-linux` machine is a remote builder (i.e., not your current machine), ensure that your current machine's `root` user can ssh into the `root` user of the remote builder, via ssh key authentication (add your computer's public rsa key into the `authorized_keys` file of the remote builder) 149 | 3. Ensure that the user you are going to deploy from on your current machine can ssh into the `root` user of the Raspberry Pi, also via ssh key authentication explained above. 150 | 151 | ## Deploy 152 | 153 | 1. Simply run `colmena apply` 154 | 155 | # Using Templates 156 | 157 | The templates are for initializing project specific nix flakes into their directories. 158 | 159 | Substitute `elixir` with the template you want in the commands below. 160 | 161 | ## Generate a template into an existing project 162 | ```shell 163 | nix flake init --template "github:fmoda3/nix-configs#elixir" 164 | ``` 165 | 166 | ## Generate a new project with a template 167 | ```shell 168 | nix flake new --template "github:fmoda3/nix-configs#elixir" ${NEW_PROJECT_DIRECTORY} 169 | ``` 170 | 171 | # Formatting 172 | 173 | This flake's formatting is set to use `nixpkgs-fmt`. Formatting works via 174 | ```shell 175 | nix fmt 176 | ``` 177 | 178 | # Pre Commit Hooks 179 | 180 | This flake uses the [pre-commit-hook](https://github.com/cachix/pre-commit-hooks.nix) project run git hooks on commit. Currently, it verifies that the flake is properly linted and formatted before commit. 181 | 182 | # Devshell 183 | 184 | This flake uses the [devshell](https://github.com/numtide/devshell) project to easily setup a dev environment when in this project's directory. It adds a few packages to the environment, as well as aliases to format, lint, and build various images. 185 | 186 | To enter the devshell without `direnv`, run 187 | 188 | ```shell 189 | nix develop 190 | ``` 191 | 192 | If you use `direnv`, it should become available anytime you are in the directory after running 193 | 194 | ```shell 195 | direnv allow 196 | ``` -------------------------------------------------------------------------------- /claude/fcis-architecture.md: -------------------------------------------------------------------------------- 1 | # Claude Code Guidelines: Functional Core, Imperative Shell 2 | 3 | ## Core Philosophy 4 | 5 | All code in this project follows the **Functional Core, Imperative Shell** (FCIS) architecture pattern. This means: 6 | 7 | - **Functional Core**: Pure, immutable business logic with no side effects 8 | - **Imperative Shell**: Thin layer handling I/O, state mutations, and external interactions 9 | 10 | ## Data Modeling Principles 11 | 12 | ### 1. Make Invalid States Unrepresentable 13 | 14 | Design data models that can only express valid states. Use sum types (sealed classes/unions) to enumerate all possible states explicitly. 15 | 16 | **Kotlin Example:** 17 | ```kotlin 18 | sealed class PaymentState { 19 | object Pending : PaymentState() 20 | data class Processing(val transactionId: String) : PaymentState() 21 | data class Completed(val transactionId: String, val receipt: Receipt) : PaymentState() 22 | data class Failed(val error: PaymentError) : PaymentState() 23 | } 24 | ``` 25 | 26 | **TypeScript Example:** 27 | ```typescript 28 | type PaymentState = 29 | | { kind: "pending" } 30 | | { kind: "processing"; transactionId: string } 31 | | { kind: "completed"; transactionId: string; receipt: Receipt } 32 | | { kind: "failed"; error: PaymentError } 33 | ``` 34 | 35 | ### 2. Data First, Behavior Second 36 | 37 | Always define your data models before implementing behavior. The shape of your data should guide the structure of your functions. 38 | 39 | ## Functional Core Guidelines 40 | 41 | ### Pure Functions Only 42 | 43 | The functional core must contain only pure functions: 44 | - No I/O operations (file system, network, database) 45 | - No random number generation 46 | - No date/time access 47 | - No logging or console output 48 | - No exceptions (use Result/Either types) 49 | 50 | ### Error Handling 51 | 52 | Use explicit error types instead of exceptions: 53 | 54 | **Kotlin:** 55 | ```kotlin 56 | sealed class Result { 57 | data class Success(val value: T) : Result() 58 | data class Failure(val error: E) : Result() 59 | } 60 | ``` 61 | 62 | **TypeScript:** 63 | ```typescript 64 | type Result = 65 | | { kind: "success"; value: T } 66 | | { kind: "failure"; error: E } 67 | ``` 68 | 69 | ### Immutability 70 | 71 | All data structures in the functional core must be immutable: 72 | - Use `val` in Kotlin, never `var` 73 | - Use `const` and `readonly` in TypeScript 74 | - Return new instances instead of modifying existing ones 75 | 76 | ## Imperative Shell Guidelines 77 | 78 | ### Minimal Logic 79 | 80 | The imperative shell should contain minimal business logic. Its responsibilities: 81 | 1. Gather inputs from external sources 82 | 2. Call functional core with inputs 83 | 3. Handle outputs/side effects based on core's results 84 | 85 | ### Dependency Injection 86 | 87 | Pass all dependencies explicitly to the shell. The functional core should never directly access external resources. 88 | 89 | **Kotlin Example:** 90 | ```kotlin 91 | class PaymentShell( 92 | private val repository: PaymentRepository, 93 | private val emailService: EmailService, 94 | private val logger: Logger 95 | ) { 96 | suspend fun processPayment(request: PaymentRequest): PaymentResult { 97 | // Imperative: Fetch data 98 | val account = repository.getAccount(request.accountId) 99 | 100 | // Functional: Process business logic 101 | val result = PaymentCore.processPayment(account, request) 102 | 103 | // Imperative: Handle side effects 104 | when (result) { 105 | is Success -> { 106 | repository.save(result.payment) 107 | emailService.sendReceipt(result.receipt) 108 | logger.info("Payment processed: ${result.payment.id}") 109 | } 110 | is Failure -> { 111 | logger.error("Payment failed: ${result.error}") 112 | } 113 | } 114 | 115 | return result 116 | } 117 | } 118 | ``` 119 | 120 | ## Testing Strategy 121 | 122 | ### Functional Core Testing 123 | 124 | - Test exhaustively with unit tests 125 | - Use property-based testing where applicable 126 | - No mocking required (pure functions) 127 | - Test all edge cases and state transitions 128 | 129 | ### Imperative Shell Testing 130 | 131 | - Use integration tests with real or in-memory implementations 132 | - Mock external dependencies sparingly 133 | - Focus on correct coordination between components 134 | 135 | ## Code Organization 136 | 137 | ### Directory Structure 138 | 139 | ``` 140 | src/ 141 | ├── core/ # Functional core 142 | │ ├── models/ # Data models and types 143 | │ ├── logic/ # Pure business logic 144 | │ └── validation/ # Pure validation functions 145 | ├── shell/ # Imperative shell 146 | │ ├── api/ # HTTP handlers 147 | │ ├── db/ # Database access 148 | │ ├── services/ # External service integrations 149 | │ └── config/ # Configuration loading 150 | └── shared/ # Shared utilities (must be pure) 151 | ``` 152 | 153 | ### Module Boundaries 154 | 155 | - Core modules must not import from shell modules 156 | - Shell modules can import from core modules 157 | - Use dependency inversion for core to define interfaces that shell implements 158 | 159 | ## Language-Specific Guidelines 160 | 161 | ### Kotlin 162 | 163 | - Prefer `data class` for models 164 | - Use `sealed class` for sum types 165 | - Leverage `copy()` for immutable updates 166 | - Use coroutines in shell, pure functions in core 167 | 168 | ### TypeScript 169 | 170 | - Use discriminated unions for sum types 171 | - Prefer `type` over `interface` for data models 172 | - Use `readonly` arrays and objects 173 | - Leverage spread operator for immutable updates 174 | 175 | ### Elixir 176 | 177 | - Pattern match extensively 178 | - Use structs for data modeling 179 | - Keep GenServers in the shell layer 180 | - Pure functions should not send/receive messages 181 | 182 | ## Common Patterns 183 | 184 | ### State Machines 185 | 186 | Model state transitions explicitly: 187 | 188 | ```kotlin 189 | fun transition(state: OrderState, event: OrderEvent): Result = 190 | when (state) { 191 | is OrderState.Draft -> when (event) { 192 | is OrderEvent.Submit -> validateOrder(state.items) 193 | .map { OrderState.Submitted(orderId = generateId(), items = state.items) } 194 | else -> Result.Failure(InvalidTransition(state, event)) 195 | } 196 | // ... other states 197 | } 198 | ``` 199 | 200 | ### Validation Pipelines 201 | 202 | Chain validations functionally: 203 | 204 | ```typescript 205 | const validateUser = (input: UserInput): Result => 206 | pipe( 207 | input, 208 | validateEmail, 209 | chain(validateAge), 210 | chain(validateUsername), 211 | map(createValidatedUser) 212 | ) 213 | ``` 214 | 215 | ## Anti-Patterns to Avoid 216 | 217 | 1. **Hidden State**: No global variables or singletons in core 218 | 2. **Implicit Dependencies**: All dependencies must be explicit parameters 219 | 3. **Mixed Concerns**: Don't mix I/O with business logic 220 | 4. **Partial Functions**: Avoid functions that can throw exceptions 221 | 5. **Stringly-Typed Code**: Use proper types instead of strings for domain concepts 222 | 223 | ## Decision Checklist 224 | 225 | When implementing a feature, ask: 226 | 227 | 1. Is the business logic pure and testable without mocks? 228 | 2. Can invalid states be represented in the data model? 229 | 3. Are all possible states explicitly modeled? 230 | 4. Is the imperative shell as thin as possible? 231 | 5. Are errors handled explicitly without exceptions? 232 | 6. Is all data immutable within the functional core? 233 | 234 | ## References 235 | 236 | - [Functional Core, Imperative Shell](https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell) 237 | - [Making Impossible States Impossible](https://www.youtube.com/watch?v=IcgmSRJHu_8) 238 | - [Parse, Don't Validate](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) --------------------------------------------------------------------------------