diff --git a/config/aichat/default.nix b/config/aichat/default.nix index 4a247aad4..8d36403ca 100644 --- a/config/aichat/default.nix +++ b/config/aichat/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/aichat/config.yaml" = { source = ./config.yaml; force = true; diff --git a/config/amp/default.nix b/config/amp/default.nix index 34cb7f5b2..2c2cc05f5 100644 --- a/config/amp/default.nix +++ b/config/amp/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."amp/settings.json" = { source = ./settings.json; }; diff --git a/config/cliproxyapi/default.nix b/config/cliproxyapi/default.nix index 05ef632f2..7d17b1c60 100644 --- a/config/cliproxyapi/default.nix +++ b/config/cliproxyapi/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { # Template config - the service wrapper injects secrets and writes to config.yaml home.file.".cli-proxy-api/config.template.yaml" = { source = ./config.template.yaml; diff --git a/config/crush/default.nix b/config/crush/default.nix index 2c435bed4..9a9380943 100644 --- a/config/crush/default.nix +++ b/config/crush/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/crush/crush.json" = { source = ./crush.json; force = true; diff --git a/config/direnv/default.nix b/config/direnv/default.nix index 41fd186e6..44da959ce 100644 --- a/config/direnv/default.nix +++ b/config/direnv/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/direnv/direnvrc" = { source = ./direnvrc; force = true; diff --git a/config/eww/default.nix b/config/eww/default.nix index 8981cbe03..4336dcd17 100644 --- a/config/eww/default.nix +++ b/config/eww/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."eww/eww.yuck" = { source = ./eww.yuck; force = true; diff --git a/config/factory/default.nix b/config/factory/default.nix index 171f10bf2..e0f734800 100644 --- a/config/factory/default.nix +++ b/config/factory/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".factory/config.json" = { source = ./config.json; force = true; diff --git a/config/gomi/default.nix b/config/gomi/default.nix index cabf18a8e..b33033aef 100644 --- a/config/gomi/default.nix +++ b/config/gomi/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."gomi/config.yaml" = { source = ./config.yaml; }; diff --git a/config/hammerspoon/default.nix b/config/hammerspoon/default.nix index cce06c31c..7c30fcd11 100644 --- a/config/hammerspoon/default.nix +++ b/config/hammerspoon/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".hammerspoon/init.lua" = { source = ./init.lua; force = true; diff --git a/config/hyprpanel/default.nix b/config/hyprpanel/default.nix index d60248e41..3ca9ccb4d 100644 --- a/config/hyprpanel/default.nix +++ b/config/hyprpanel/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { programs.hyprpanel = { enable = true; systemd.enable = false; diff --git a/config/hyprshell/default.nix b/config/hyprshell/default.nix index a41fc90e2..991ccce31 100644 --- a/config/hyprshell/default.nix +++ b/config/hyprshell/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."hyprshell/config.toml" = { source = ./config.toml; force = true; diff --git a/config/jj/default.nix b/config/jj/default.nix index e5dc36161..5a70d4988 100644 --- a/config/jj/default.nix +++ b/config/jj/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."jj/config.toml" = { source = ./config.toml; }; diff --git a/config/karabiner/default.nix b/config/karabiner/default.nix index 4e174ac5c..f626e44ef 100644 --- a/config/karabiner/default.nix +++ b/config/karabiner/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/karabiner/karabiner.json" = { source = ./karabiner.json; force = true; diff --git a/config/nwg-dock-hyprland/default.nix b/config/nwg-dock-hyprland/default.nix index 34e63a68a..4b4dc23fc 100644 --- a/config/nwg-dock-hyprland/default.nix +++ b/config/nwg-dock-hyprland/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."nwg-dock-hyprland/style.css" = { source = ./style.css; force = true; diff --git a/config/nwg-drawer/default.nix b/config/nwg-drawer/default.nix index b758226f0..3fe13b6d1 100644 --- a/config/nwg-drawer/default.nix +++ b/config/nwg-drawer/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."nwg-drawer/drawer.css" = { source = ./drawer.css; force = true; diff --git a/config/opencode/default.nix b/config/opencode/default.nix index f6a8f1ff7..b949333d1 100644 --- a/config/opencode/default.nix +++ b/config/opencode/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/opencode/opencode.jsonc" = { source = ./opencode.jsonc; force = true; diff --git a/config/pi/default.nix b/config/pi/default.nix index 871791507..fb2eff792 100644 --- a/config/pi/default.nix +++ b/config/pi/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".pi/agent/models.json" = { source = ./models.json; force = true; diff --git a/config/starship/default.nix b/config/starship/default.nix index c07312c70..67d71589d 100644 --- a/config/starship/default.nix +++ b/config/starship/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".config/starship.toml" = { source = ./starship.toml; force = true; diff --git a/config/walker/default.nix b/config/walker/default.nix index 76d1b67ae..2cce53e62 100644 --- a/config/walker/default.nix +++ b/config/walker/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."walker/config.toml" = { source = ./config.toml; force = true; diff --git a/config/worktrunk/default.nix b/config/worktrunk/default.nix index c917974b2..e67e70542 100644 --- a/config/worktrunk/default.nix +++ b/config/worktrunk/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."worktrunk/config.toml" = { source = ./config.toml; force = true; diff --git a/config/zellij/default.nix b/config/zellij/default.nix index 335b7cc41..4416e52c1 100644 --- a/config/zellij/default.nix +++ b/config/zellij/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { xdg.configFile."zellij/config.kdl" = { source = ./config.kdl; }; diff --git a/home-manager/modules/obsidian/default.nix b/home-manager/modules/obsidian/default.nix index 88ac2ba69..78ddda4ce 100644 --- a/home-manager/modules/obsidian/default.nix +++ b/home-manager/modules/obsidian/default.nix @@ -17,9 +17,14 @@ let # so they get pulled into the closure automatically without needing to # appear directly on PATH. Only this shim is exposed as `obsidian`, # which is exactly what memory-wiki probes for. - obsidianHeadless = pkgs.writeShellScriptBin "obsidian" '' - exec ${pkgs.xvfb-run}/bin/xvfb-run -a ${pkgs.obsidian}/bin/obsidian "$@" - ''; + obsidianHeadless = pkgs.writeShellScriptBin "obsidian" ( + builtins.readFile ( + pkgs.replaceVars ./obsidian-headless.sh { + xvfbRun = pkgs.xvfb-run; + obsidian = pkgs.obsidian; + } + ) + ); in # Only enable on kyber (gateway host) — desktops already get pkgs.obsidian # directly via home-manager/packages/default.nix. diff --git a/home-manager/modules/obsidian/obsidian-headless.sh b/home-manager/modules/obsidian/obsidian-headless.sh new file mode 100644 index 000000000..e33facd22 --- /dev/null +++ b/home-manager/modules/obsidian/obsidian-headless.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +exec @xvfbRun@/bin/xvfb-run -a @obsidian@/bin/obsidian "$@" diff --git a/home-manager/programs/fish/functions/_coxel_function.fish b/home-manager/programs/fish/functions/_coxel_function.fish index a88b31645..382a98220 100644 --- a/home-manager/programs/fish/functions/_coxel_function.fish +++ b/home-manager/programs/fish/functions/_coxel_function.fish @@ -1,13 +1,13 @@ -function _coxel_function --description "Run Codex with a free-form prompt using the local Gemma model" - # Run Codex with a free-form prompt (spaces allowed) using the local Gemma model +function _coxel_function --description "Run Codex with a free-form prompt using the local Qwen model" + # Run Codex with a free-form prompt (spaces allowed) using the local Qwen model # Usage: cxel [] if test (count $argv) -gt 0; and contains -- "$argv[1]" --resume -r --continue -c codex resume $argv[2] else if test (count $argv) -eq 0 - codex --oss --local-provider lmstudio --model 'lmstudio-community/gemma-4-e4b-it' --full-auto -c model_reasoning_effort=minimal + codex --oss --local-provider lmstudio --model 'qwen/qwen3.5-9b' --full-auto -c model_reasoning_effort=minimal else set -l prompt (string join " " -- $argv) - codex exec --oss --local-provider lmstudio --model 'lmstudio-community/gemma-4-e4b-it' --full-auto -c model_reasoning_effort=minimal -- "$prompt" + codex exec --oss --local-provider lmstudio --model 'qwen/qwen3.5-9b' --full-auto -c model_reasoning_effort=minimal -- "$prompt" end end diff --git a/home-manager/programs/fish/functions/_coxel_function.tpl.fish b/home-manager/programs/fish/functions/_coxel_function.tpl.fish index 1e584a73c..ba8ed3a75 100644 --- a/home-manager/programs/fish/functions/_coxel_function.tpl.fish +++ b/home-manager/programs/fish/functions/_coxel_function.tpl.fish @@ -1,13 +1,13 @@ -function _coxel_function --description "Run Codex with a free-form prompt using the local Gemma model" - # Run Codex with a free-form prompt (spaces allowed) using the local Gemma model +function _coxel_function --description "Run Codex with a free-form prompt using the local Qwen model" + # Run Codex with a free-form prompt (spaces allowed) using the local Qwen model # Usage: cxel [] if test (count $argv) -gt 0; and contains -- "$argv[1]" --resume -r --continue -c codex resume $argv[2] else if test (count $argv) -eq 0 - codex --oss --local-provider lmstudio --model '__GEMMA__' --full-auto -c model_reasoning_effort=minimal + codex --oss --local-provider lmstudio --model '__QWEN_LOCAL__' --full-auto -c model_reasoning_effort=minimal else set -l prompt (string join " " -- $argv) - codex exec --oss --local-provider lmstudio --model '__GEMMA__' --full-auto -c model_reasoning_effort=minimal -- "$prompt" + codex exec --oss --local-provider lmstudio --model '__QWEN_LOCAL__' --full-auto -c model_reasoning_effort=minimal -- "$prompt" end end diff --git a/home-manager/programs/fish/functions/_coxelh_function.fish b/home-manager/programs/fish/functions/_coxelh_function.fish index 8efe1fdb7..4d3d4a83e 100644 --- a/home-manager/programs/fish/functions/_coxelh_function.fish +++ b/home-manager/programs/fish/functions/_coxelh_function.fish @@ -1,5 +1,5 @@ -function _coxelh_function --description "Run Codex headlessly with the local Gemma model" - # Prompt for input and run Codex with the local Gemma model +function _coxelh_function --description "Run Codex headlessly with the local Qwen model" + # Prompt for input and run Codex with the local Qwen model # Usage: coxelh set -l prompt @@ -14,5 +14,5 @@ function _coxelh_function --description "Run Codex headlessly with the local Gem return 1 end - codex exec --oss --local-provider lmstudio --model 'lmstudio-community/gemma-4-e4b-it' --full-auto -c model_reasoning_effort=minimal -- "$prompt" + codex exec --oss --local-provider lmstudio --model 'qwen/qwen3.5-9b' --full-auto -c model_reasoning_effort=minimal -- "$prompt" end diff --git a/home-manager/programs/fish/functions/_coxelh_function.tpl.fish b/home-manager/programs/fish/functions/_coxelh_function.tpl.fish index b17986219..cfd44104c 100644 --- a/home-manager/programs/fish/functions/_coxelh_function.tpl.fish +++ b/home-manager/programs/fish/functions/_coxelh_function.tpl.fish @@ -1,5 +1,5 @@ -function _coxelh_function --description "Run Codex headlessly with the local Gemma model" - # Prompt for input and run Codex with the local Gemma model +function _coxelh_function --description "Run Codex headlessly with the local Qwen model" + # Prompt for input and run Codex with the local Qwen model # Usage: coxelh set -l prompt @@ -14,5 +14,5 @@ function _coxelh_function --description "Run Codex headlessly with the local Gem return 1 end - codex exec --oss --local-provider lmstudio --model '__GEMMA__' --full-auto -c model_reasoning_effort=minimal -- "$prompt" + codex exec --oss --local-provider lmstudio --model '__QWEN_LOCAL__' --full-auto -c model_reasoning_effort=minimal -- "$prompt" end diff --git a/home-manager/programs/fish/functions/_ocxel_function.fish b/home-manager/programs/fish/functions/_ocxel_function.fish index 8c4e1f409..4343dfe83 100644 --- a/home-manager/programs/fish/functions/_ocxel_function.fish +++ b/home-manager/programs/fish/functions/_ocxel_function.fish @@ -1,17 +1,17 @@ -function _ocxel_function --description "Run OpenCode with a free-form prompt using the local Gemma model" - # Run OpenCode with a free-form prompt (spaces allowed) using the local Gemma model +function _ocxel_function --description "Run OpenCode with a free-form prompt using the local Qwen model" + # Run OpenCode with a free-form prompt (spaces allowed) using the local Qwen model # Usage: ocxel [] if test (count $argv) -gt 0; and contains -- "$argv[1]" --resume -r --continue -c if test (count $argv) -gt 1 - opencode -m 'lmstudio/lmstudio-community/gemma-4-e4b-it' --session "$argv[2]" + opencode -m 'lmstudio/qwen/qwen3.5-9b' --session "$argv[2]" else - opencode -m 'lmstudio/lmstudio-community/gemma-4-e4b-it' --continue + opencode -m 'lmstudio/qwen/qwen3.5-9b' --continue end else if test (count $argv) -eq 0 - opencode -m 'lmstudio/lmstudio-community/gemma-4-e4b-it' + opencode -m 'lmstudio/qwen/qwen3.5-9b' else set -l prompt (string join " " -- $argv) - opencode run "$prompt" -m 'lmstudio/lmstudio-community/gemma-4-e4b-it' + opencode run "$prompt" -m 'lmstudio/qwen/qwen3.5-9b' end end diff --git a/home-manager/programs/fish/functions/_ocxel_function.tpl.fish b/home-manager/programs/fish/functions/_ocxel_function.tpl.fish index d7da19fee..d87cdcfdb 100644 --- a/home-manager/programs/fish/functions/_ocxel_function.tpl.fish +++ b/home-manager/programs/fish/functions/_ocxel_function.tpl.fish @@ -1,17 +1,17 @@ -function _ocxel_function --description "Run OpenCode with a free-form prompt using the local Gemma model" - # Run OpenCode with a free-form prompt (spaces allowed) using the local Gemma model +function _ocxel_function --description "Run OpenCode with a free-form prompt using the local Qwen model" + # Run OpenCode with a free-form prompt (spaces allowed) using the local Qwen model # Usage: ocxel [] if test (count $argv) -gt 0; and contains -- "$argv[1]" --resume -r --continue -c if test (count $argv) -gt 1 - opencode -m 'lmstudio/__GEMMA__' --session "$argv[2]" + opencode -m 'lmstudio/__QWEN_LOCAL__' --session "$argv[2]" else - opencode -m 'lmstudio/__GEMMA__' --continue + opencode -m 'lmstudio/__QWEN_LOCAL__' --continue end else if test (count $argv) -eq 0 - opencode -m 'lmstudio/__GEMMA__' + opencode -m 'lmstudio/__QWEN_LOCAL__' else set -l prompt (string join " " -- $argv) - opencode run "$prompt" -m 'lmstudio/__GEMMA__' + opencode run "$prompt" -m 'lmstudio/__QWEN_LOCAL__' end end diff --git a/home-manager/programs/fish/functions/_ocxelh_function.fish b/home-manager/programs/fish/functions/_ocxelh_function.fish index 8349e60bd..fe545f632 100644 --- a/home-manager/programs/fish/functions/_ocxelh_function.fish +++ b/home-manager/programs/fish/functions/_ocxelh_function.fish @@ -1,5 +1,5 @@ -function _ocxelh_function --description "Run OpenCode headlessly with the local Gemma model" - # Prompt for input and run OpenCode with the local Gemma model +function _ocxelh_function --description "Run OpenCode headlessly with the local Qwen model" + # Prompt for input and run OpenCode with the local Qwen model # Usage: ocxelh set -l prompt @@ -14,5 +14,5 @@ function _ocxelh_function --description "Run OpenCode headlessly with the local return 1 end - opencode run "$prompt" -m 'lmstudio/lmstudio-community/gemma-4-e4b-it' + opencode run "$prompt" -m 'lmstudio/qwen/qwen3.5-9b' end diff --git a/home-manager/programs/fish/functions/_ocxelh_function.tpl.fish b/home-manager/programs/fish/functions/_ocxelh_function.tpl.fish index 178f6b137..421eb1b5f 100644 --- a/home-manager/programs/fish/functions/_ocxelh_function.tpl.fish +++ b/home-manager/programs/fish/functions/_ocxelh_function.tpl.fish @@ -1,5 +1,5 @@ -function _ocxelh_function --description "Run OpenCode headlessly with the local Gemma model" - # Prompt for input and run OpenCode with the local Gemma model +function _ocxelh_function --description "Run OpenCode headlessly with the local Qwen model" + # Prompt for input and run OpenCode with the local Qwen model # Usage: ocxelh set -l prompt @@ -14,5 +14,5 @@ function _ocxelh_function --description "Run OpenCode headlessly with the local return 1 end - opencode run "$prompt" -m 'lmstudio/__GEMMA__' + opencode run "$prompt" -m 'lmstudio/__QWEN_LOCAL__' end diff --git a/home-manager/programs/fish/functions/_pixel_function.fish b/home-manager/programs/fish/functions/_pixel_function.fish index d6ca26074..8b695f0b4 100644 --- a/home-manager/programs/fish/functions/_pixel_function.fish +++ b/home-manager/programs/fish/functions/_pixel_function.fish @@ -3,11 +3,11 @@ function _pixel_function --description "Run Pi with a free-form prompt using the # Usage: pixel [] if test (count $argv) -gt 0; and contains -- "$argv[1]" --resume -r --continue -c - pi --model 'lmstudio/qwen3.5-0.8b-optiq' --resume $argv[2] + pi --model 'lmstudio/qwen/qwen3.5-9b' --resume $argv[2] else if test (count $argv) -eq 0 - pi --model 'lmstudio/qwen3.5-0.8b-optiq' + pi --model 'lmstudio/qwen/qwen3.5-9b' else set -l prompt (string join " " -- $argv) - pi --model 'lmstudio/qwen3.5-0.8b-optiq' "$prompt" + pi --model 'lmstudio/qwen/qwen3.5-9b' "$prompt" end end diff --git a/home-manager/programs/fish/functions/_pixelh_function.fish b/home-manager/programs/fish/functions/_pixelh_function.fish index 9f707d026..0018c97c9 100644 --- a/home-manager/programs/fish/functions/_pixelh_function.fish +++ b/home-manager/programs/fish/functions/_pixelh_function.fish @@ -14,5 +14,5 @@ function _pixelh_function --description "Run Pi headlessly with the local Qwen m return 1 end - pi --model 'lmstudio/qwen3.5-0.8b-optiq' -p "$prompt" + pi --model 'lmstudio/qwen/qwen3.5-9b' -p "$prompt" end diff --git a/home-manager/programs/ssh/default.nix b/home-manager/programs/ssh/default.nix index d79b0139f..f12ab892c 100644 --- a/home-manager/programs/ssh/default.nix +++ b/home-manager/programs/ssh/default.nix @@ -1,5 +1,4 @@ -_: -{ +_: { home.file.".ssh/rc" = { source = ./rc; force = true; diff --git a/spec/coverage_spec.sh b/spec/coverage_spec.sh index d00479837..ad3cc9dab 100644 --- a/spec/coverage_spec.sh +++ b/spec/coverage_spec.sh @@ -257,6 +257,7 @@ home-manager/modules/local-scripts/clipboard-paste.sh home-manager/modules/local-scripts/notify-local.sh home-manager/modules/local-scripts/tmux-bridge.sh home-manager/modules/npm-globals/install-npm-globals.sh +home-manager/modules/obsidian/obsidian-headless.sh home-manager/modules/uv-globals/install-uv-globals.sh home-manager/programs/neovim/run_tests.sh home-manager/programs/tmux/session-logger.sh diff --git a/spec/obsidian_headless_spec.sh b/spec/obsidian_headless_spec.sh new file mode 100644 index 000000000..db8251382 --- /dev/null +++ b/spec/obsidian_headless_spec.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# shellcheck disable=SC2329 + +Describe 'home-manager/modules/obsidian/obsidian-headless.sh' +SCRIPT="$PWD/home-manager/modules/obsidian/obsidian-headless.sh" + +Describe 'script properties' +It 'uses bash shebang' +When run bash -c "head -1 '$SCRIPT'" +The output should include '#!/usr/bin/env bash' +End + +It 'passes bash syntax check after replacing placeholders' +When run bash -c "sed -e 's|@xvfbRun@|/usr|g' -e 's|@obsidian@|/usr|g' '$SCRIPT' | bash -n" +The status should be success +End +End + +Describe 'placeholder references' +It 'references xvfb-run via placeholder' +When run bash -c "grep '@xvfbRun@' '$SCRIPT'" +The output should include '@xvfbRun@' +End + +It 'references obsidian via placeholder' +When run bash -c "grep '@obsidian@' '$SCRIPT'" +The output should include '@obsidian@' +End + +It 'uses exec to replace the process' +When run bash -c "grep '^exec ' '$SCRIPT'" +The output should include 'exec' +End + +It 'passes all arguments through' +When run bash -c "grep '[\$]@' '$SCRIPT'" +The output should include '$@' +End + +It 'uses xvfb-run with auto-servernum flag' +When run bash -c "grep '\\-a' '$SCRIPT'" +The output should include '-a' +End +End + +End