refactor!: switch to dendritic pattern

BREAKING CHANGE: complete reorganization of the repository
This commit is contained in:
2026-09-30 18:36:06 +02:00
parent 12684b4e9c
commit 5f4a7a4a42
323 changed files with 7117 additions and 7380 deletions
+50
View File
@@ -0,0 +1,50 @@
{config, ...}: let
m = config.flake.modules.homeManager;
in {
flake.modules.homeManager.ai = {
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.home.dev.ai;
jsonFormat = pkgs.formats.json {};
in {
imports = [
m.claude
m.ollama
m.opencode
];
options.home.dev.ai = {
enable = mkEnableOption "Enables AI features";
lmStudio = mkOption {
default = cfg.enable;
example = true;
description = "Enables LM Studio. Enabled by default when AI is enabled.";
};
mcpServers = mkOption {
inherit (jsonFormat) type;
default = {};
};
};
config = {
home = mkIf cfg.enable {
dev.ai = {
claude = {
enable = mkDefault cfg.enable;
mcpServers = mkDefault cfg.mcpServers;
};
ollama.enable = mkDefault cfg.enable;
opencode.enable = mkDefault cfg.enable;
};
packages = lists.optional cfg.lmStudio pkgs.lmstudio;
};
programs.mcp = mkIf (cfg.mcpServers != {}) {
enable = true;
servers = cfg.mcpServers;
};
};
};
}
+30
View File
@@ -0,0 +1,30 @@
{
flake.modules.homeManager.claude = {
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.home.dev.ai.claude;
jsonFormat = pkgs.formats.json {};
in {
options.home.dev.ai.claude = {
enable = mkEnableOption "Enables Claude-related packages";
mcpServers = mkOption {
inherit (jsonFormat) type;
default = {};
};
};
config = mkIf cfg.enable {
home.packages = let
claude-jj = pkgs.writeShellScriptBin "claude-jj" ''
${pkgs.claude-code}/bin/claude --append-system-prompt 'CRITICAL: This repository uses Jujutsu (jj), NOT git. Never use git commands. Use jj equivalents.' "$@"
'';
in [claude-jj pkgs.sox];
programs.claude-code = {
inherit (cfg) enable mcpServers;
};
};
};
}
+34
View File
@@ -0,0 +1,34 @@
{
flake.modules.homeManager.ollama = {
config,
lib,
...
}:
with lib; let
cfg = config.home.dev.ai.ollama;
in {
options.home.dev.ai.ollama = {
enable = mkEnableOption "Enables Ollama";
gpu = mkOption {
type = types.nullOr (types.enum [false "rocm" "cuda"]);
example = "rocm";
default = null;
description = "Which type of GPU should be used for hardware acceleration";
};
};
config = {
services.ollama = mkIf cfg.enable {
inherit (cfg) enable;
acceleration = cfg.gpu;
host = "0.0.0.0";
environmentVariables = {
OLLAMA_CONTEXT_LENGTH = "8192";
OLLAMA_MAX_LOADED_MODELS = "1";
OLLAMA_KEEP_ALIVE = "10m";
};
};
home.sessionVariables.OLLAMA_API_BASE = "http://${config.services.ollama.host}:11434/";
};
};
}
+102
View File
@@ -0,0 +1,102 @@
{
flake.modules.homeManager.opencode = {
config,
lib,
pkgs,
bunBaseline,
...
}:
with lib; let
cfg = config.home.dev.ai.opencode;
# On x86_64-linux CPUs without AVX2, use the baseline bun variant
# when building opencode - the regular `bun` from nixpkgs requires
# AVX2 and crashes on older hardware, such as my Thinkpad x220’s
# Intel Core i5 2640M.
needsBaselineBun =
pkgs.stdenv.hostPlatform.isx86_64 && !pkgs.stdenv.hostPlatform.avx2Support;
defaultPackageCli =
if needsBaselineBun
then pkgs.opencode.override {bun = bunBaseline;}
else pkgs.opencode;
defaultPackageDesktop =
if needsBaselineBun
then pkgs.opencode-desktop.override {bun = bunBaseline;}
else pkgs.opencode-desktop;
corsList = domains: lists.remove "" (lists.forEach (strings.splitString "," domains) trim);
in {
options.home.dev.ai.opencode = {
enable = mkEnableOption "Enables OpenCode";
package = mkOption {
type = types.package;
default = defaultPackageCli;
description = "The CLI package for OpenCode";
};
settings = mkOption {
type = types.json;
default = {};
};
tui = mkOption {
type = types.json;
default = {};
};
desktop = {
enable = mkEnableOption "Enables the desktop app";
package = mkOption {
type = types.package;
default = defaultPackageDesktop;
description = "The desktop package for OpenCode";
};
};
web = {
enable = mkEnableOption "Enables OpenCode web";
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
example = [
"--hostname"
"0.0.0.0"
];
};
cors = mkOption {
type = types.nullOr (types.either types.str types.path);
default = null;
example = "opencode.example.com,code.example.com";
description = ''
Either a string containing the domain allowed to connect to OpenCode’s web instance, or a file containing the target value. The latter is useful when using secret management if you don’t want to publicize the hostname of your OpenCode instance.
If you want to use multiple domains, you can separate them with a comma.
'';
};
mdns = {
enable = mkEnableOption "Enables mDNS with OpenCode";
hostname = mkOption {
type = types.nullOr types.str;
default = null;
example = "opencode.local";
};
};
};
};
config.programs.opencode = mkIf cfg.enable {
inherit (cfg) enable tui package;
enableMcpIntegration = true;
extraPackages = with pkgs; [uv] ++ lists.optional cfg.desktop.enable cfg.desktop.package;
settings =
{
server = mkIf cfg.web.mdns.enable {
mdns = true;
mdnsDomain = mkIf (cfg.web.mdns.hostname != null) cfg.web.mdns.hostname;
cors = corsList cfg.web.cors;
};
}
// cfg.settings;
web = {
inherit (cfg.web) enable extraArgs;
};
};
};
}