Skip to content

Modules

Modules are the core of NixKraken. Together, they form a declarative system that generates GitKraken configuration.

This document explains NixKraken's module organization, how modules compose into the final configuration, and module-specific behaviors. It is intended for contributors extending NixKraken or integrating custom behavior.

WARNING

Contributors should be familiar with the NixOS module system.

Terminology used in this document:

  • options: NixKraken module options (input)
  • settings: GitKraken configuration options (output)
  • module / submodule: NixKraken modules; "submodule" as defined by the NixOS module system

Structure and Organization

Each subdirectory within the modules directory implements a focused, single-purpose module for a specific aspect of GitKraken configuration.

Directory structure of the module system:

txt
.
├── modules
│   ├── datetime
│   ├── git
│   ├── gpg
│   ├── graph
│   ├── notifications
│   ├── profiles
│   ├── ssh
│   ├── tools
│   ├── ui
│   ├── user
│   └── root-options.nix
└── module.nix

The primary entry point is module.nix. It is responsible for:

The root-options.nix file defines top-level options.

This modular approach improves maintainability and clarifies how configuration aspects interact.

Option Scoping

Most GitKraken settings are profile-specific; some are global. To support both scopes, a module may define:

  • app-options.nix: global (application-wide) options
  • profile-options.nix: profile-specific options

INFO

The profiles module is an intentional exception to this pattern. It aggregates per-profile options across modules and constructs additional profile instances.

This design lets you define global and default-profile behavior in top-level modules (e.g., nixkraken.gpg, nixkraken.user, etc.) and reuse per-profile options for additional profiles under nixkraken.profiles.*.

Example structure of the git module:

txt
modules/git
├── app-options.nix
├── default.nix
└── profile-options.nix
  • app-options.nix declares global options
  • profile-options.nix declares per-profile options
  • default.nix defines:

This structure is especially useful with the profiles module, which aggregates all per-profile options into a meta-module to define additional profiles. The following diagram illustrate this:

flowchart TD top-level["Top-level module"] git["Git module"] profiles["Profiles module"] other["Other module"] git-app-opts["app-options.nix"] git-profile-opts["profile-options.nix"] other-profile-opts["profile-options.nix"] other-app-opts["app-options.nix"] top-level--->git top-level-->profiles top-level--->other profiles--->|profiles.git|git-profile-opts profiles--->|profiles.<module>|other-profile-opts subgraph git-module [ ] git--->git-app-opts git-->git-profile-opts end subgraph other-modules [ ] other-->other-profile-opts other--->other-app-opts end

INFO

Some modules (e.g., the ui module) split options across multiple files for maintainability due to the large number of options.

They still adhere to the global vs. profile option boundaries via app-options.nix and profile-options.nix.

This may evolve into nested submodules.

Settings Composition

To centralize application of GitKraken configuration, each submodule writes its evaluated global settings as an attribute set to an internal option _submoduleSettings.<moduleName>.

The top-level module merges all entries in _submoduleSettings to form the final GitKraken configuration and serializes it to JSON before passing it to the gk-configure package, which writes to the location expected by GitKraken (i.e., ~/.gitkraken/config).

The following diagram illustrates the flow:

flowchart TB git["Git module"] datetime["Datetime module"] other["Other module"] top-level["Top-level module<br/><sub><sup>Merged in settings</sup></sub>"] configure["gk-configure"] gitkraken["GitKraken configuration file<br/><sub><sup>~/.gitkraken/config</sup></sub>"] git--->|_submoduleSettings.git|top-level datetime--->|_submoduleSettings.datetime|top-level other--->|_submoduleSettings.whatever|top-level top-level-->|builtins.toJSON settings|configure configure-->|writes|gitkraken

Profiles Module

As noted earlier, most GitKraken settings are per-profile. The profiles module manages both the default profile and additional profiles.

The default profile is identified via an internal option isDefault. It uses GitKraken's fixed identifier and sources its name and avatar from the root options defaultProfile.name and defaultProfile.icon.

About profile identifiers

GitKraken uses UUIDs stripped of dashes to identify profiles. The default profile uses a fixed identifier (d6e5a8ca26e14325a4275fc33b17e16f), while additional profiles use randomly generated identifiers.

Because Nix does not natively generate UUIDs, NixKraken derives stable, UUID-shaped identifiers via a utility function that:

  • takes a seed string as input
  • hashes the seed using the SHA-512 algorithm
  • slices the hash into five segments matching UUID lengths (8, 4, 4, 4, 12)
  • concatenates the segments with dashes

This produces deterministic identifiers for profiles with unique names. Although we could hash the profile name and truncate to 32 characters, we use this function because it is also needed elsewhere.

A safeguard prevents duplicate profile names, ensuring uniqueness of identifiers.

Because NixKraken supports multiple profiles, a builder function emits GitKraken settings for each profile.

As with global settings, per-profile settings are serialized to JSON and passed, with the profile identifier, to the gk-configure package, which writes them to ~/.gitkraken/profiles/<id>/profile.

The following diagram illustrates the flow:

flowchart TD config["NixKraken configuration"] default["Default profile"] a["Profile A"] b["Profile B"] builder["Profile builder"] configure["gk-configure<br/><sub><sup>Profile settings + identifier</sup></sub>"] gitkraken["GitKraken profile setting<br/><sub><sup>~/.gitkraken/profiles/&lt;id&gt;/profile</sup></sub>"] config-->default config-->a config-->b default-->builder a-->builder b-->builder builder-->|for each profile|configure configure-->|writes|gitkraken

Inheritance

Additional profiles inherit recursively from the default profile via lib.recursiveUpdate function. Per-profile options override inherited defaults where keys overlap.

Safeguards

To improve the user experience and catch issues early, NixKraken modules make extensive use of warnings and assertions.

Examples of safeguards:

  • enabling commit/tag signing without a signing key
  • enabling notification topics while notifications are disabled
  • mutually exclusive options such as package and version

Use an assertion when a configuration would be invalid or non-deterministic. Use a warning for configurations that are valid but likely unintended.

Messages should be informative and cite the relevant options.

Example (good):

SSH keys (ssh.privateKey, ssh.publicKey) cannot be set when local SSH agent is used (ssh.useLocalAgent)

As opposed to:

Cannot set ssh.privateKey

Released under the MIT License