Skip to content

Programs

Source directory: modules/programs/

1password.nix

modules/programs/1password.nix

Options: enable

Options declaration (Nix)
  options.security.onepassword = {
    enable = mkEnableOption {
      description = "Enable 1Password integration";
      default = false;
    };
  }

chrome-pwa-icons.nix

modules/programs/chrome-pwa-icons.nix

Chrome PWA Icon Sync

Chromium-based browsers install PWAs as .desktop files referencing icons by bare name (Icon=chrome--Profile_) but store the actual PNG files only inside ~/.config/google-chrome/Profile /Web Applications/Manifest Resources//Icons/. That path is not on any XDG icon search path, so launchers (COSMIC, GNOME) fall back to a generic placeholder.

This module installs a per-user oneshot service + timer that symlinks every Chrome-downloaded PWA icon into ~/.local/share/icons/hicolor/x/apps/ and refreshes the GTK icon cache. Idempotent, fast, and reversible.

Tracked in issue #397.

  • Enable option: Chrome PWA icon sync into the XDG hicolor tree
Options declaration (Nix)
  options.modules.programs.chrome-pwa-icons = {
    enable = lib.mkEnableOption "Chrome PWA icon sync into the XDG hicolor tree";

    user = lib.mkOption {
      type = lib.types.str;
      example = "alice";
      description = ''
        User whose Chrome profiles will be scanned and whose
        ~/.local/share/icons/hicolor tree will receive the symlinks.
      '';
    };

    syncIntervalMinutes = lib.mkOption {
      type = lib.types.ints.between 0 1440;
      default = 15;
      description = ''
        How often the timer fires while the user is logged in. Set to 0 to
        disable the timer (the service still runs once at login).
      '';
    };
  }

claude-code-managed.nix

modules/programs/claude-code-managed.nix

Claude Code managed-settings.json

Renders /etc/claude-code/managed-settings.json — Claude Code's highest- precedence config layer. The CLI reads this file but NEVER writes to it, making the read-only nix-store backing both safe and correct.

Use this for settings the user must not be able to disable from the CLI (PARR hooks, baseline permissions, apiKeyHelper). User-scope preferences like statusLine and enabledPlugins should NOT live here — see the init- template pattern in home/development/claude-code-lsp.nix instead.

Reference: https://code.claude.com/docs/en/settings.md Tracked in issue #398.

  • Enable option: Claude Code managed-settings.json (read-only baseline)
  • Enable option: Claude Code notification hooks (Notification/Stop/SubagentStop)
Options declaration (Nix)
  options.modules.programs.claude-code-managed = {
    enable = lib.mkEnableOption "Claude Code managed-settings.json (read-only baseline)";

    settings = lib.mkOption {
      type = lib.types.attrsOf lib.types.anything;
      default = { };
      example = lib.literalExpression ''
        {
          permissions.deny = [ "Bash(rm -rf /*)" ];
          apiKeyHelper = "/run/wrappers/bin/op-claude-key";
        }
      '';
      description = ''
        Settings to write into /etc/claude-code/managed-settings.json.
        Claude Code reads this with highest precedence and never writes back.
        Anything here is effectively unmodifiable from the CLI/UI.
      '';
    };

    parrProtocol.enable = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Inject the PARR (Plan, Act, Reflect, Revise) UserPromptSubmit hook.
        Equivalent to the previous programs.claudeCode.hooks.enableParrProtocol
        option, but enforced from managed scope so the user cannot disable it
        by editing ~/.claude/settings.json.
      '';
    };

    baselineAllow.enable = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Auto-approve a curated baseline of safe, read-only / build / test /
        format commands (nix build/eval/fmt, just validate/test-*, read-only
        git, statix/deadnix/alejandra) via managed-scope permissions.allow, so
        routine repo operations never trigger a permission prompt. System-
        mutating commands (deploys, nixos-rebuild, git commit/push, sudo, rm)
        are deliberately excluded and still require explicit approval.
      '';
    };

    subagentMetadata.enable = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Publish the live Claude Code Task-subagent count to herdr as a pane
        metadata token, rendered by the $agents entry in the sidebar row
        config (home/development/herdr.nix).

        Subagents run in-process with no PTY, so herdr cannot represent them as
        their own agent rows; this makes an otherwise invisible fan-out visible
        on the parent pane. No-ops outside a herdr pane.
      '';
    };

    deployGuard.enable = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Veto Claude Code Bash calls that would activate a new generation on
        p510 (the headless media server), via a managed-scope PreToolUse hook.
        Enforces the standing "never deploy p510 without explicit approval"
        rule mechanically instead of relying on the model remembering it.

        Building (`nix build .#nixosConfigurations.p510...`) and read-only ssh
        are unaffected, as is the user's own interactive shell.
      '';
    };

    busPeekWake.enable = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Wake an agent at the end of its turn when a bus message names it.

        The bus is pull-only and an agent reads it once, at the start of a
        session -- before it has done the work that produces a question, and
        before anyone has answered. So a question reaches its target only by
        luck, and the room looks dead while it is busy. This makes the delivery
        deterministic: a Stop hook peeks for messages naming this session and,
        if there are any, denies the stop and hands them back.

        Wakes once per message (peek keeps its own cursor, separate from
        read_new's), never on the session's own messages, and never on a turn
        that is already a Stop-hook continuation. A homeserver that is
        unreachable is not an error -- the turn simply ends.
      '';
    };
# … truncated — see source link above

claude-router-cli.nix

modules/programs/claude-router-cli.nix

Claude Code router CLI — switches repos between local Ollama (via LiteLLM on p620) and cloud Anthropic API per repository.

Phase 3 of docs/plans/2026-05-22-ollama-p620-litellm-design.md. Depends on Phase 1 (Ollama on p620) + Phase 2 (LiteLLM proxy on p620).

What this module installs:

  1. claude-router CLI on system PATH: claude-router use-ollama — writes /.claude/settings.json with ANTHROPIC_BASE_URL pointing at the right router URL (loopback on p620, Tailscale on razer) claude-router use-claude — removes the override (back to api.anthropic.com) claude-router use-default — alias for use-claude claude-router status — prints which backend the current repo uses

  2. claude-router-key helper script for Claude Code's apiKeyHelper: inspects ANTHROPIC_BASE_URL and emits the right bearer key:

  3. router URL → /run/agenix/api-router- (LiteLLM bearer)
  4. default URL → /run/agenix/api-anthropic (cloud Anthropic) This is auto-wired into modules.programs.claude-code-managed.settings.apiKeyHelper.

  5. Slash command markdown files at /etc/claude-code/commands/ for users who want the slash-command UX. Home Manager users can symlink them into ~/.claude/commands/ (a HM stanza is provided in the user's profile for olafkfreund — see Users/olafkfreund/profile.nix).

Network endpoint selection happens at write-time in claude-router use-ollama: - on p620 → http://127.0.0.1:4000 (loopback, sub-ms) - elsewhere → https://p620..ts.net/router (Tailscale)

The bearer key for the router and the key for cloud Anthropic are BOTH agenix-managed; the user never types them.

  • Enable option: claude-router CLI + apiKeyHelper for routing Claude Code between local Ollama and cloud Anthropic
Options declaration (Nix)
  options.modules.programs.claude-router-cli = {
    enable = lib.mkEnableOption "claude-router CLI + apiKeyHelper for routing Claude Code between local Ollama and cloud Anthropic";

    routerHostKey = lib.mkOption {
      type = lib.types.str;
      default = "api-router-${config.networking.hostName}";
      description = ''
        Name of the agenix secret holding this host's bearer key for the
        LiteLLM router. Defaults to api-router-<hostname>.
      '';
    };
  }

dconf.nix

modules/programs/dconf.nix

No option declarations; see source for implementation.

default.nix

modules/programs/default.nix

No option declarations; see source for implementation.

droidcam.nix

modules/programs/droidcam.nix

Options: enable

Options declaration (Nix)
  options.media.droidcam = {
    enable = mkEnableOption {
      description = "Enable Droicam";
      default = false;
    };
  }

firefox.nix

modules/programs/firefox.nix

No option declarations; see source for implementation.

gnupg.nix

modules/programs/gnupg.nix

Options: enable

Options declaration (Nix)
  options.security.gnupg = {
    enable = mkEnableOption {
      default = false;
      description = "Enable GnuPG";
    };
  }

nix-ld.nix

modules/programs/nix-ld.nix

No option declarations; see source for implementation.

stream_deck.nix

modules/programs/stream_deck.nix

Options: enable

Options declaration (Nix)
  options.program.streamcontroller = {
    enable = mkEnableOption {
      description = "Enable Streamcontroller";
      default = false;
    };
  }

wshowkeys.nix

modules/programs/wshowkeys.nix

No option declarations; see source for implementation.

yt-x.nix

modules/programs/yt-x.nix

  • Enable option: yt-x terminal YouTube browser

Options: enable

Options declaration (Nix)
  options.features.programs.yt-x = {
    enable = mkEnableOption "yt-x terminal YouTube browser";
  }