switch default shell to zsh and adopt catppuccin mocha
This commit is contained in:
parent
418f0701bc
commit
a58e842817
15 changed files with 391 additions and 160 deletions
|
|
@ -7,8 +7,8 @@ So far, the dotfiles only used for my macOS configuration, maybe in the future I
|
|||
## Core System
|
||||
|
||||
- OS: macOS (nix-darwin)
|
||||
- Shell: nushell with starship prompt
|
||||
- Terminal: kitty with gruvbox theme
|
||||
- Shell: Zsh with Oh My Zsh and Starship; Nushell is available through `nu`
|
||||
- Terminal: Kitty with Catppuccin Mocha theme
|
||||
- Package Management: mix of nix and homebrew
|
||||
|
||||
## Developer Tools
|
||||
|
|
@ -22,7 +22,7 @@ So far, the dotfiles only used for my macOS configuration, maybe in the future I
|
|||
|
||||
## AI Tools
|
||||
|
||||
- CLI-based tools: codex, crush, opencode, claude code
|
||||
- CLI-based tools: codex, crush, claude code
|
||||
- Custom z.ai gateway wrapper for claude code
|
||||
- Secret management with SOPS-nix
|
||||
|
||||
|
|
|
|||
|
|
@ -4,26 +4,49 @@
|
|||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
globalEnvironmentSecretNames = [
|
||||
"ANTHROPIC_API_KEY"
|
||||
"BRAVE_SEARCH_API_KEY"
|
||||
"CROF_API_KEY"
|
||||
"EXA_API_KEY"
|
||||
"FAL_API_KEY"
|
||||
"FIRECRAWL_API_KEY"
|
||||
"GROQ_API_KEY"
|
||||
"KIMI_API_KEY"
|
||||
"MOONSHOT_API_KEY"
|
||||
"OPENAI_API_KEY"
|
||||
"OPENROUTER_API_KEY"
|
||||
"ZAI_API_KEY"
|
||||
];
|
||||
in
|
||||
{
|
||||
# Import shared cross-platform home configuration
|
||||
imports = [
|
||||
../../home/base.nix
|
||||
../../home/shell/nushell.nix
|
||||
../../home/shell/zsh.nix
|
||||
./programs/aerospace
|
||||
./programs/kitty.nix
|
||||
];
|
||||
|
||||
# Darwin-specific secrets configuration.
|
||||
# Materialize the whole encrypted env map once, then let Nushell load it.
|
||||
# Decrypt each global environment variable to a separate runtime file.
|
||||
# Zsh and Nushell load the files without evaluating shell source text.
|
||||
rsydn.secrets = {
|
||||
enable = lib.mkDefault true;
|
||||
defaultSopsFile = ../../../secrets/global-env.sops.yaml;
|
||||
secrets = {
|
||||
"global-env" = {
|
||||
format = "yaml";
|
||||
key = "";
|
||||
path = "${config.xdg.configHome}/secrets/global-env.yaml";
|
||||
};
|
||||
};
|
||||
secrets = lib.genAttrs globalEnvironmentSecretNames (name: {
|
||||
format = "yaml";
|
||||
key = name;
|
||||
path = "${config.xdg.configHome}/secrets/global-env/${name}";
|
||||
});
|
||||
};
|
||||
|
||||
home.activation.ensureGlobalEnvironmentSecretDir =
|
||||
lib.hm.dag.entryBetween [ "sops-nix" ] [ "writeBoundary" ]
|
||||
''
|
||||
rm -f "${config.xdg.configHome}/secrets/global-env.yaml"
|
||||
mkdir -p "${config.xdg.configHome}/secrets/global-env"
|
||||
chmod 700 "${config.xdg.configHome}/secrets/global-env"
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,34 +4,49 @@
|
|||
enable = true;
|
||||
|
||||
settings = {
|
||||
# JetBrainsMono Nerd Font renders the Starship powerline icons.
|
||||
font_family = "JetBrainsMono Nerd Font";
|
||||
font_size = 13.0;
|
||||
|
||||
background_opacity = "0.9";
|
||||
confirm_os_window_close = 0;
|
||||
enabled_layouts = "splits,stack";
|
||||
|
||||
# Gruvbox colors
|
||||
background = "#282828";
|
||||
foreground = "#ebdbb2";
|
||||
cursor = "#ebdbb2";
|
||||
cursor_text_color = "#282828";
|
||||
selection_background = "#ebdbb2";
|
||||
selection_foreground = "#282828";
|
||||
# Catppuccin Mocha colors (catppuccin/kitty themes/mocha.conf)
|
||||
background = "#1e1e2e";
|
||||
foreground = "#cdd6f4";
|
||||
cursor = "#f5e0dc";
|
||||
cursor_text_color = "#1e1e2e";
|
||||
selection_background = "#f5e0dc";
|
||||
selection_foreground = "#1e1e2e";
|
||||
|
||||
color0 = "#282828";
|
||||
color1 = "#cc241d";
|
||||
color2 = "#98971a";
|
||||
color3 = "#d79921";
|
||||
color4 = "#458588";
|
||||
color5 = "#b16286";
|
||||
color6 = "#689d6a";
|
||||
color7 = "#a89984";
|
||||
color8 = "#928374";
|
||||
color9 = "#fb4934";
|
||||
color10 = "#b8bb26";
|
||||
color11 = "#fabd2f";
|
||||
color12 = "#83a598";
|
||||
color13 = "#d3869b";
|
||||
color14 = "#8ec07c";
|
||||
color15 = "#ebdbb2";
|
||||
# Kitty window border colors
|
||||
active_border_color = "#b4befe";
|
||||
inactive_border_color = "#6c7086";
|
||||
|
||||
# Tab bar colors
|
||||
active_tab_foreground = "#11111b";
|
||||
active_tab_background = "#cba6f7";
|
||||
inactive_tab_foreground = "#cdd6f4";
|
||||
inactive_tab_background = "#181825";
|
||||
tab_bar_background = "#11111b";
|
||||
|
||||
color0 = "#45475a";
|
||||
color1 = "#f38ba8";
|
||||
color2 = "#a6e3a1";
|
||||
color3 = "#f9e2af";
|
||||
color4 = "#89b4fa";
|
||||
color5 = "#f5c2e7";
|
||||
color6 = "#94e2d5";
|
||||
color7 = "#bac2de";
|
||||
color8 = "#585b70";
|
||||
color9 = "#f38ba8";
|
||||
color10 = "#a6e3a1";
|
||||
color11 = "#f9e2af";
|
||||
color12 = "#89b4fa";
|
||||
color13 = "#f5c2e7";
|
||||
color14 = "#94e2d5";
|
||||
color15 = "#a6adc8";
|
||||
};
|
||||
|
||||
keybindings = {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ in
|
|||
default = [
|
||||
"bitwarden"
|
||||
"brave-browser"
|
||||
"font-jetbrains-mono"
|
||||
"font-jetbrains-mono-nerd-font"
|
||||
"pgadmin4"
|
||||
"spotify"
|
||||
"vesktop"
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@
|
|||
|
||||
users.users.${user} = {
|
||||
home = lib.mkDefault "/Users/${user}";
|
||||
# Use the Home Manager nushell which has proper config setup
|
||||
shell = "/etc/profiles/per-user/${user}/bin/nu";
|
||||
# Use the macOS system Zsh as the login shell. Nushell remains available as `nu`.
|
||||
shell = "/bin/zsh";
|
||||
};
|
||||
|
||||
system = {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@
|
|||
|
||||
rsydn.devTools = {
|
||||
enable = lib.mkDefault true;
|
||||
# Note: jetbrains-mono removed - installed via Homebrew cask (font-jetbrains-mono)
|
||||
# Note: jetbrains-mono removed - installed via Homebrew cask (font-jetbrains-mono-nerd-font)
|
||||
# due to nixpkgs-unstable syrupy test failures breaking the font's Python build deps
|
||||
packages = with pkgs; [
|
||||
age
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ in
|
|||
programs.direnv = {
|
||||
enable = true;
|
||||
enableNushellIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
nix-direnv.enable = true;
|
||||
silent = cfg.silent;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ require("lazy").setup({
|
|||
version = false,
|
||||
},
|
||||
|
||||
install = { colorscheme = { "gruvbox", "habamax" } },
|
||||
install = { colorscheme = { "catppuccin-mocha", "habamax" } },
|
||||
|
||||
checker = { enabled = false },
|
||||
change_detection = { notify = false },
|
||||
|
|
|
|||
|
|
@ -2,13 +2,8 @@ return {
|
|||
-- gruvbox
|
||||
{
|
||||
"ellisonleao/gruvbox.nvim",
|
||||
lazy = false,
|
||||
priority = 1000,
|
||||
lazy = true,
|
||||
opts = {},
|
||||
config = function()
|
||||
require("gruvbox").setup({})
|
||||
vim.cmd.colorscheme("gruvbox")
|
||||
end,
|
||||
},
|
||||
|
||||
-- tokyonight
|
||||
|
|
@ -21,10 +16,12 @@ return {
|
|||
-- catppuccin
|
||||
{
|
||||
"catppuccin/nvim",
|
||||
lazy = true,
|
||||
lazy = false,
|
||||
priority = 1000,
|
||||
name = "catppuccin",
|
||||
opts = {
|
||||
flavour = "mocha",
|
||||
term_colors = true,
|
||||
lsp_styles = {
|
||||
underlines = {
|
||||
errors = { "undercurl" },
|
||||
|
|
@ -60,6 +57,10 @@ return {
|
|||
-- which_key = true,
|
||||
-- },
|
||||
},
|
||||
config = function(_, opts)
|
||||
require("catppuccin").setup(opts)
|
||||
vim.cmd.colorscheme("catppuccin-mocha")
|
||||
end,
|
||||
-- specs = {
|
||||
-- {
|
||||
-- "akinsho/bufferline.nvim",
|
||||
|
|
|
|||
|
|
@ -181,22 +181,24 @@ in
|
|||
|
||||
$env.NIX_PROFILES = "/run/current-system/sw ${config.home.profileDirectory}"
|
||||
|
||||
# Load globally scoped sops-managed environment variables.
|
||||
let global_secrets_file = "${config.xdg.configHome}/secrets/global-env.yaml"
|
||||
# Load each globally scoped sops-managed environment variable.
|
||||
let global_secrets_dir = "${config.xdg.configHome}/secrets/global-env"
|
||||
|
||||
def --env load-global-secrets [secret_file: string] {
|
||||
if ($secret_file | path exists) {
|
||||
let secret_values = (open $secret_file)
|
||||
def --env load-global-secrets [secret_dir: string] {
|
||||
if ($secret_dir | path exists) {
|
||||
let secret_values = (
|
||||
ls $secret_dir
|
||||
| reduce -f {} {|entry, acc|
|
||||
let name = ($entry.name | path basename)
|
||||
let value = (open --raw $entry.name | str trim)
|
||||
$acc | upsert $name $value
|
||||
}
|
||||
)
|
||||
|
||||
$secret_values
|
||||
| transpose name value
|
||||
| reduce -f {} {|entry, acc|
|
||||
$acc | upsert $entry.name ($entry.value | into string)
|
||||
}
|
||||
| load-env
|
||||
$secret_values | load-env
|
||||
}
|
||||
}
|
||||
|
||||
load-global-secrets $global_secrets_file
|
||||
load-global-secrets $global_secrets_dir
|
||||
'';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
enable = lib.mkDefault true;
|
||||
enableFishIntegration = true;
|
||||
enableNushellIntegration = true;
|
||||
enableZshIntegration = true;
|
||||
settings = lib.importTOML ./starship.toml;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
"$schema" = "https://starship.rs/config-schema.json"
|
||||
|
||||
format = """
|
||||
[](color_orange)\
|
||||
[](peach)\
|
||||
$os\
|
||||
$username\
|
||||
[](bg:color_yellow fg:color_orange)\
|
||||
[](bg:yellow fg:peach)\
|
||||
$directory\
|
||||
[](fg:color_yellow bg:color_aqua)\
|
||||
[](fg:yellow bg:teal)\
|
||||
$git_branch\
|
||||
$git_status\
|
||||
[](fg:color_aqua bg:color_blue)\
|
||||
[](fg:teal bg:blue)\
|
||||
$c\
|
||||
$cpp\
|
||||
$rust\
|
||||
|
|
@ -20,32 +20,49 @@ $java\
|
|||
$kotlin\
|
||||
$haskell\
|
||||
$python\
|
||||
[](fg:color_blue bg:color_bg3)\
|
||||
[](fg:blue bg:surface0)\
|
||||
$docker_context\
|
||||
$conda\
|
||||
$pixi\
|
||||
[](fg:color_bg3 bg:color_bg1)\
|
||||
[](fg:surface0 bg:base)\
|
||||
$time\
|
||||
[ ](fg:color_bg1)\
|
||||
[ ](fg:base)\
|
||||
$line_break$character"""
|
||||
|
||||
palette = "gruvbox_dark"
|
||||
palette = "catppuccin_mocha"
|
||||
|
||||
[palettes.gruvbox_dark]
|
||||
color_fg0 = "#fbf1c7"
|
||||
color_bg1 = "#3c3836"
|
||||
color_bg3 = "#665c54"
|
||||
color_blue = "#458588"
|
||||
color_aqua = "#689d6a"
|
||||
color_green = "#98971a"
|
||||
color_orange = "#d65d0e"
|
||||
color_purple = "#b16286"
|
||||
color_red = "#cc241d"
|
||||
color_yellow = "#d79921"
|
||||
# Official Catppuccin Mocha palette (catppuccin/starship themes/mocha.toml)
|
||||
[palettes.catppuccin_mocha]
|
||||
rosewater = "#f5e0dc"
|
||||
flamingo = "#f2cdcd"
|
||||
pink = "#f5c2e7"
|
||||
mauve = "#cba6f7"
|
||||
red = "#f38ba8"
|
||||
maroon = "#eba0ac"
|
||||
peach = "#fab387"
|
||||
yellow = "#f9e2af"
|
||||
green = "#a6e3a1"
|
||||
teal = "#94e2d5"
|
||||
sky = "#89dceb"
|
||||
sapphire = "#74c7ec"
|
||||
blue = "#89b4fa"
|
||||
lavender = "#b4befe"
|
||||
text = "#cdd6f4"
|
||||
subtext1 = "#bac2de"
|
||||
subtext0 = "#a6adc8"
|
||||
overlay2 = "#9399b2"
|
||||
overlay1 = "#7f849c"
|
||||
overlay0 = "#6c7086"
|
||||
surface2 = "#585b70"
|
||||
surface1 = "#45475a"
|
||||
surface0 = "#313244"
|
||||
base = "#1e1e2e"
|
||||
mantle = "#181825"
|
||||
crust = "#11111b"
|
||||
|
||||
[os]
|
||||
disabled = false
|
||||
style = "bg:color_orange fg:color_fg0"
|
||||
style = "bg:peach fg:crust"
|
||||
|
||||
[os.symbols]
|
||||
Windows = ""
|
||||
|
|
@ -72,12 +89,12 @@ Pop = ""
|
|||
|
||||
[username]
|
||||
show_always = true
|
||||
style_user = "bg:color_orange fg:color_fg0"
|
||||
style_root = "bg:color_orange fg:color_fg0"
|
||||
style_user = "bg:peach fg:crust"
|
||||
style_root = "bg:peach fg:crust"
|
||||
format = "[ $user ]($style)"
|
||||
|
||||
[directory]
|
||||
style = "fg:color_fg0 bg:color_yellow"
|
||||
style = "fg:crust bg:yellow"
|
||||
format = "[ $path ]($style)"
|
||||
truncation_length = 3
|
||||
truncation_symbol = "…/"
|
||||
|
|
@ -91,90 +108,90 @@ Developer = " "
|
|||
|
||||
[git_branch]
|
||||
symbol = ""
|
||||
style = "bg:color_aqua"
|
||||
format = "[[ $symbol $branch ](fg:color_fg0 bg:color_aqua)]($style)"
|
||||
style = "bg:teal"
|
||||
format = "[[ $symbol $branch ](fg:crust bg:teal)]($style)"
|
||||
|
||||
[git_status]
|
||||
style = "bg:color_aqua"
|
||||
format = "[[($all_status$ahead_behind )](fg:color_fg0 bg:color_aqua)]($style)"
|
||||
style = "bg:teal"
|
||||
format = "[[($all_status$ahead_behind )](fg:crust bg:teal)]($style)"
|
||||
|
||||
[nodejs]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[c]
|
||||
symbol = " "
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[cpp]
|
||||
symbol = " "
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[rust]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[golang]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[php]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[java]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[kotlin]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[haskell]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[python]
|
||||
symbol = ""
|
||||
style = "bg:color_blue"
|
||||
format = "[[ $symbol( $version) ](fg:color_fg0 bg:color_blue)]($style)"
|
||||
style = "bg:blue"
|
||||
format = "[[ $symbol( $version) ](fg:crust bg:blue)]($style)"
|
||||
|
||||
[docker_context]
|
||||
symbol = ""
|
||||
style = "bg:color_bg3"
|
||||
format = "[[ $symbol( $context) ](fg:#83a598 bg:color_bg3)]($style)"
|
||||
style = "bg:surface0"
|
||||
format = "[[ $symbol( $context) ](fg:teal bg:surface0)]($style)"
|
||||
|
||||
[conda]
|
||||
style = "bg:color_bg3"
|
||||
format = "[[ $symbol( $environment) ](fg:#83a598 bg:color_bg3)]($style)"
|
||||
style = "bg:surface0"
|
||||
format = "[[ $symbol( $environment) ](fg:teal bg:surface0)]($style)"
|
||||
|
||||
[pixi]
|
||||
style = "bg:color_bg3"
|
||||
format = "[[ $symbol( $version)( $environment) ](fg:color_fg0 bg:color_bg3)]($style)"
|
||||
style = "bg:surface0"
|
||||
format = "[[ $symbol( $version)( $environment) ](fg:text bg:surface0)]($style)"
|
||||
|
||||
[time]
|
||||
disabled = false
|
||||
time_format = "%R"
|
||||
style = "bg:color_bg1"
|
||||
format = "[[ $time ](fg:color_fg0 bg:color_bg1)]($style)"
|
||||
style = "bg:base"
|
||||
format = "[[ $time ](fg:text bg:base)]($style)"
|
||||
|
||||
[line_break]
|
||||
disabled = false
|
||||
|
||||
[character]
|
||||
disabled = false
|
||||
success_symbol = "[](bold fg:color_green)"
|
||||
error_symbol = "[](bold fg:color_red)"
|
||||
vimcmd_symbol = "[](bold fg:color_green)"
|
||||
vimcmd_replace_one_symbol = "[](bold fg:color_purple)"
|
||||
vimcmd_replace_symbol = "[](bold fg:color_purple)"
|
||||
vimcmd_visual_symbol = "[](bold fg:color_yellow)"
|
||||
success_symbol = "[](bold fg:green)"
|
||||
error_symbol = "[](bold fg:red)"
|
||||
vimcmd_symbol = "[](bold fg:green)"
|
||||
vimcmd_replace_one_symbol = "[](bold fg:mauve)"
|
||||
vimcmd_replace_symbol = "[](bold fg:mauve)"
|
||||
vimcmd_visual_symbol = "[](bold fg:yellow)"
|
||||
|
|
@ -14,7 +14,15 @@
|
|||
prefix = "C-a";
|
||||
escapeTime = 0;
|
||||
aggressiveResize = true;
|
||||
plugins = [ { plugin = pkgs.tmuxPlugins.gruvbox; } ];
|
||||
plugins = [
|
||||
{
|
||||
plugin = pkgs.tmuxPlugins.catppuccin;
|
||||
extraConfig = ''
|
||||
set -g @catppuccin_flavor "mocha"
|
||||
set -g @catppuccin_window_status_style "rounded"
|
||||
'';
|
||||
}
|
||||
];
|
||||
extraConfig = ''
|
||||
# Terminal configuration for proper colors and features
|
||||
set-option -g default-terminal "screen-256color"
|
||||
|
|
@ -50,9 +58,10 @@
|
|||
bind J resize-pane -D 5
|
||||
bind K resize-pane -U 5
|
||||
bind L resize-pane -R 5
|
||||
# Ensure tmux panes spawn login nu so Starship integration runs
|
||||
set -g default-shell "${config.home.profileDirectory}/bin/nu"
|
||||
set -g default-command "${config.home.profileDirectory}/bin/nu --login"
|
||||
# Start Zsh by default and keep Nushell available on prefix + C-n.
|
||||
set -g default-shell "/bin/zsh"
|
||||
set -g default-command "/bin/zsh --login"
|
||||
bind-key C-n new-window -n nushell "${config.home.profileDirectory}/bin/nu --login"
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
|
|||
136
modules/home/shell/zsh.nix
Normal file
136
modules/home/shell/zsh.nix
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
{ config, ... }:
|
||||
{
|
||||
programs.zsh = {
|
||||
enable = true;
|
||||
enableCompletion = true;
|
||||
dotDir = config.home.homeDirectory;
|
||||
|
||||
oh-my-zsh = {
|
||||
enable = true;
|
||||
plugins = [
|
||||
"git"
|
||||
"sudo"
|
||||
];
|
||||
};
|
||||
|
||||
shellAliases.ssh = "kitten ssh";
|
||||
|
||||
profileExtra = ''
|
||||
if [[ -x /opt/homebrew/bin/brew ]]; then
|
||||
eval "$(/opt/homebrew/bin/brew shellenv)"
|
||||
elif [[ -x /usr/local/bin/brew ]]; then
|
||||
eval "$(/usr/local/bin/brew shellenv)"
|
||||
fi
|
||||
|
||||
[[ -r "$HOME/.orbstack/shell/init.zsh" ]] && source "$HOME/.orbstack/shell/init.zsh"
|
||||
'';
|
||||
|
||||
initContent = ''
|
||||
typeset -U path PATH
|
||||
path=(
|
||||
"$HOME/.cache/.bun/bin"
|
||||
"$HOME/.local/bin"
|
||||
$path
|
||||
"$HOME/.lmstudio/bin"
|
||||
)
|
||||
export PATH
|
||||
|
||||
_load_global_secrets() {
|
||||
local secret_dir="''${XDG_CONFIG_HOME:-$HOME/.config}/secrets/global-env"
|
||||
local secret_file name value
|
||||
|
||||
[[ -d "$secret_dir" ]] || return 0
|
||||
|
||||
for secret_file in "$secret_dir"/*(N.); do
|
||||
name="''${secret_file:t}"
|
||||
[[ "$name" =~ '^[A-Za-z_][A-Za-z0-9_]*$' ]] || continue
|
||||
value="$(<"$secret_file")"
|
||||
export "$name=$value"
|
||||
done
|
||||
}
|
||||
|
||||
_load_global_secrets
|
||||
unfunction _load_global_secrets
|
||||
|
||||
dotfiles-qa() (
|
||||
local dotfiles_dir="${config.home.homeDirectory}/Development/dotfiles"
|
||||
|
||||
print -P "%F{green}Running dotfiles QA validation...%f"
|
||||
cd "$dotfiles_dir" || return 1
|
||||
|
||||
print -P "%F{blue}1. Formatting Nix files...%f"
|
||||
nix fmt . || {
|
||||
print -P "%F{red}Formatting failed.%f"
|
||||
return 1
|
||||
}
|
||||
|
||||
print -P "%F{blue}2. Running flake checks...%f"
|
||||
XDG_CACHE_HOME="$dotfiles_dir/.cache" nix flake check || {
|
||||
print -P "%F{red}Flake checks failed.%f"
|
||||
return 1
|
||||
}
|
||||
|
||||
print -P "%F{blue}3. Building the Darwin configuration...%f"
|
||||
darwin-rebuild build --flake "$dotfiles_dir#macbook-pro" || {
|
||||
print -P "%F{red}Darwin build failed.%f"
|
||||
return 1
|
||||
}
|
||||
|
||||
print -P "%F{green}Core QA checks passed.%f"
|
||||
)
|
||||
|
||||
bd-init() {
|
||||
if [[ ! -d .git && ! -f .git ]]; then
|
||||
print -P "%F{red}Error: not in a Git repository.%f"
|
||||
print "Initialize one with: git init"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -e .beads ]]; then
|
||||
print -P "%F{yellow}Beads is already initialized in this project.%f"
|
||||
return 0
|
||||
fi
|
||||
|
||||
bd init || return
|
||||
print -P "%F{green}Beads initialized.%f"
|
||||
print "Next steps:"
|
||||
print ' bd create --title "Your task" --type feature'
|
||||
print " bd ready"
|
||||
}
|
||||
|
||||
bd-ready() {
|
||||
if [[ ! -e .beads ]]; then
|
||||
print -P "%F{red}Not a Beads project. Run bd-init first.%f"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local ready_tasks
|
||||
ready_tasks="$(bd ready --json)" || return
|
||||
|
||||
if [[ "$(print -r -- "$ready_tasks" | jq 'length')" == 0 ]]; then
|
||||
print -P "%F{yellow}No ready tasks.%f"
|
||||
return 0
|
||||
fi
|
||||
|
||||
print -P "%F{green}Ready tasks:%f"
|
||||
print -r -- "$ready_tasks" | jq -r '
|
||||
.[] |
|
||||
"[\(.id)] \(.title)\n Type: \(.type) | Priority: \(.priority) | Status: \(.status)" +
|
||||
(if ((.description // "") | length) > 0 then "\n \(.description)" else "" end) +
|
||||
"\n"
|
||||
'
|
||||
}
|
||||
|
||||
bd-sync() {
|
||||
if [[ ! -e .beads ]]; then
|
||||
print -P "%F{red}Not a Beads project.%f"
|
||||
return 1
|
||||
fi
|
||||
|
||||
print -P "%F{blue}Syncing Beads database...%f"
|
||||
bd sync || return
|
||||
print -P "%F{green}Sync complete.%f"
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
|
@ -1,41 +1,46 @@
|
|||
# Secrets with sops-nix
|
||||
|
||||
This repo wires [`sops-nix`](https://github.com/Mic92/sops-nix) into the Home Manager profile so secrets are decrypted on-demand into `~/.config/secrets`. The module is enabled by default and auto-generates an Age key if one does not already exist. Only the *encrypted* payloads under `secrets/*.sops.yaml` are meant to live in git; decrypted files never leave your machine.
|
||||
This repository uses [`sops-nix`](https://github.com/Mic92/sops-nix) with Home Manager. SOPS keeps encrypted values in Git. Home Manager decrypts each global environment variable to a separate runtime file under `~/.config/secrets/global-env/`.
|
||||
|
||||
## One-time setup
|
||||
1. Ensure `age` and `sops` are available (e.g. `nix develop` or `nix profile install nixpkgs#age nixpkgs#sops`).
|
||||
2. Generate or import an Age key. Either let Home Manager create one automatically on first activation or run `age-keygen -o ~/.config/sops/age/keys.txt` yourself.
|
||||
3. Capture the public half with `age-keygen -y -f ~/.config/sops/age/keys.txt` and add it to the `recipients` list in each encrypted file (`age1…`). Commit the public key under version control or share it through your password manager so other hosts can decrypt.
|
||||
4. (Optional) Store the private key securely in macOS Keychain or 1Password (`security add-generic-password …`) so rebuilds work without manual prompts.
|
||||
|
||||
## Managing secrets
|
||||
- Global shell env vars live in one encrypted YAML file: `secrets/global-env.sops.yaml`.
|
||||
- Home Manager decrypts that file to `~/.config/secrets/global-env.yaml` during activation.
|
||||
- Nushell reads `global-env.yaml` on startup and exports each top-level key as an environment variable.
|
||||
- Only the encrypted file is tracked in git; plaintext stays local.
|
||||
1. Enter `nix develop` so `age` and `sops` are available.
|
||||
2. Generate or import an Age key. Home Manager can generate one during activation. You can also run:
|
||||
|
||||
Example Darwin configuration:
|
||||
```bash
|
||||
age-keygen -o ~/.config/sops/age/keys.txt
|
||||
```
|
||||
|
||||
```nix
|
||||
rsydn.secrets = {
|
||||
enable = true;
|
||||
defaultSopsFile = ../../../secrets/global-env.sops.yaml;
|
||||
secrets."global-env" = {
|
||||
format = "yaml";
|
||||
key = "";
|
||||
path = "${config.xdg.configHome}/secrets/global-env.yaml";
|
||||
};
|
||||
};
|
||||
3. Get the public key:
|
||||
|
||||
```bash
|
||||
age-keygen -y -f ~/.config/sops/age/keys.txt
|
||||
```
|
||||
|
||||
4. Add the public key as a recipient in each encrypted SOPS file.
|
||||
5. Store the private key in a secure backup such as 1Password or macOS Keychain.
|
||||
|
||||
## Global environment secrets
|
||||
|
||||
The encrypted source is `secrets/global-env.sops.yaml`. It contains a flat map of environment variable names and encrypted values.
|
||||
|
||||
Home Manager declares each key in `modules/darwin/home/default.nix`. During activation, sops-nix writes one mode `0400` file per key:
|
||||
|
||||
```text
|
||||
~/.config/secrets/global-env/OPENAI_API_KEY
|
||||
~/.config/secrets/global-env/ANTHROPIC_API_KEY
|
||||
```
|
||||
|
||||
Create or update global env vars by running:
|
||||
Zsh and Nushell read these files and export each filename as an environment variable. The loaders do not evaluate secret values as shell code.
|
||||
|
||||
Edit the encrypted source with:
|
||||
|
||||
```bash
|
||||
SOPS_AGE_KEY_FILE=$HOME/.config/sops/age/keys.txt \
|
||||
sops secrets/global-env.sops.yaml
|
||||
```
|
||||
|
||||
Add entries like:
|
||||
Use a flat YAML structure:
|
||||
|
||||
```yaml
|
||||
OPENAI_API_KEY: sk-...
|
||||
|
|
@ -43,21 +48,42 @@ ANTHROPIC_API_KEY: sk-ant-...
|
|||
GITHUB_TOKEN: ghp_...
|
||||
```
|
||||
|
||||
After `darwin-rebuild switch --flake .#macbook-pro`, the decrypted file is refreshed and every new Nushell session automatically gets:
|
||||
When you add or remove a key, also update `globalEnvironmentSecretNames` in `modules/darwin/home/default.nix`. Then apply the configuration:
|
||||
|
||||
```bash
|
||||
darwin-rebuild switch --flake .#macbook-pro
|
||||
```
|
||||
|
||||
Open a new Zsh or Nushell session after activation. Access values as follows:
|
||||
|
||||
```zsh
|
||||
print -r -- "$OPENAI_API_KEY"
|
||||
```
|
||||
|
||||
```nu
|
||||
$env.OPENAI_API_KEY
|
||||
$env.ANTHROPIC_API_KEY
|
||||
$env.GITHUB_TOKEN
|
||||
```
|
||||
|
||||
For secrets that should stay file-based instead of being auto-exported, you can still declare extra entries under `rsydn.secrets.secrets` with their own `path`, `format`, and `key`.
|
||||
Do not print real secret values during routine validation. Test only whether a variable exists.
|
||||
|
||||
## File-based secrets
|
||||
|
||||
Secrets that applications consume as files should stay file-based. Declare each entry under `rsydn.secrets.secrets` with its own `path`, `format`, and `key`.
|
||||
|
||||
For project-specific environment variables, use an encrypted project file with `sops exec-env` through direnv. Do not add project secrets to the global shell environment.
|
||||
|
||||
## Rotating keys
|
||||
If you regenerate your Age key, re-encrypt the file with the new recipient (`sops updatekeys secrets/global-env.sops.yaml`) and re-run `darwin-rebuild --dry-run --flake .#macbook-pro` to verify the deployment. Remember to remove old recipients so machines without access can no longer decrypt.
|
||||
|
||||
## Frequently asked questions
|
||||
- **Where do encrypted files live?** In this repo under `secrets/*.sops.yaml`; they are safe to commit.
|
||||
- **Where does plaintext live?** At runtime under `~/.config/secrets/*` (managed by Home Manager). Keep permissions tight and never add these paths to git.
|
||||
- **How do I share secrets with another machine?** Copy the Age public key from that machine into the `recipients` list, re-run `sops updatekeys`, commit, then pull and rebuild on the other host.
|
||||
- **Can I keep using `.env`?** Yes—encrypt it (e.g. `secrets/project.env.sops`) and load it with `sops exec-env` inside `direnv` so per-project shells receive the decrypted variables without storing them on disk.
|
||||
If you replace an Age key, update the recipients:
|
||||
|
||||
```bash
|
||||
sops updatekeys secrets/global-env.sops.yaml
|
||||
```
|
||||
|
||||
Remove old recipients, then validate the configuration:
|
||||
|
||||
```bash
|
||||
darwin-rebuild --dry-run --flake .#macbook-pro
|
||||
```
|
||||
|
||||
Only encrypted SOPS files belong in Git. Never add decrypted files from `~/.config/secrets/`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue