diff --git a/README.md b/README.md
index 2ffa21f..ea9d7aa 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,31 @@
-# Configuration and various sundries
+# NixOS Config
 
-IT in a box.
+IT in a box!
+
+## Bootstrapping from a fresh NixOS installation
+
+1. Install NixOS
+2. Clone this repo:
+
+   ```
+   nix-shell -p git --command 'git clone https://patagia.dev/dln/nixos-config.git'
+   ```
+
+3. Ensure host configuration exists at `./nixos-config/hosts/${HOSTNAME}` and contains at minimum the hardware configuration. The NixOS installer will write this out to `/etc/nixos/hardware-configuration.nix`.
+4. Apply configuration:
+   ```
+   sudo nixos-rebuild boot --flake ./nixos-config#${HOSTNAME}
+   ```
+
+## Use
+
+1. Clone this repo somewhere convenient, like `~/src/shelman/nixos-config`
+2. Apply configuration: `just switch`
+
+## Update
+
+Update nixpkgs and switch: `just update`
+
+# Home Manager
+
+`just home-switch`
diff --git a/common/base.nix b/common/base.nix
index 9207bf3..5eb3b4e 100644
--- a/common/base.nix
+++ b/common/base.nix
@@ -51,18 +51,6 @@
     '';
   };
 
-  services.avahi = {
-    nssmdns4 = true;
-    enable = true;
-    ipv4 = true;
-    ipv6 = true;
-    publish = {
-      enable = true;
-      addresses = true;
-      workstation = true;
-    };
-  };
-
   # Open ports in the firewall.
   # networking.firewall.allowedTCPPorts = [ ... ];
   # networking.firewall.allowedUDPPorts = [ ... ];
diff --git a/common/desktop.nix b/common/desktop.nix
index b8a467e..52cc9d4 100644
--- a/common/desktop.nix
+++ b/common/desktop.nix
@@ -16,30 +16,31 @@ in
     environment.systemPackages = with pkgs; [ gnome-ssh-askpass4 ];
 
     # Excluding some GNOME applications from the default install
-    environment.gnome.excludePackages = (
-      with pkgs;
-      [
+    environment.gnome.excludePackages =
+      (with pkgs; [
+        gnome-connections
+        gnome-photos
+        gnome-tour
+        snapshot
+      ])
+      ++ (with pkgs; [
         atomix # puzzle game
         baobab # disk usage analyzer
         cheese # webcam tool
         epiphany # web browser
         geary # email reader
         gnome-clocks
-        gnome-connections
+        gnome-contacts
         gnome-disk-utility
         gnome-logs
         gnome-music
-        gnome-photos
         gnome-terminal
-        gnome-tour
-        snapshot
         hitori # sudoku game
         iagno # go game
         simple-scan
         tali # poker game
         yelp # help viewer
-      ]
-    );
+      ]);
 
     fonts = {
       fontDir.enable = true;
@@ -47,26 +48,27 @@ in
         allowBitmaps = false;
         antialias = true;
         defaultFonts = {
-          monospace = [ "Berkeley Mono" ];
           serif = [ "Liberation Serif" ];
           sansSerif = [ "Inter" ];
         };
         hinting.enable = true;
         hinting.style = "slight";
+        subpixel.rgba = "rgb";
       };
       packages = with pkgs; [
         inter
+        jetbrains-mono
         liberation_ttf
         monaspace
-        nerd-fonts.symbols-only
+        (pkgs.nerdfonts.override { fonts = [ "JetBrainsMono" ]; })
         noto-fonts
         noto-fonts-cjk-sans
         noto-fonts-color-emoji
+        roboto
         ubuntu_font_family
       ];
     };
 
-    programs.ssh.enableAskPassword = true;
     programs.ssh.askPassword = "${pkgs.gnome-ssh-askpass4}/bin/gnome-ssh-askpass4";
     programs.ssh.startAgent = true;
 
@@ -92,7 +94,7 @@ in
       xkb.variant = "us";
     };
 
-    services.pulseaudio.enable = false;
+    hardware.pulseaudio.enable = false;
     security.rtkit.enable = true;
     services.pipewire = {
       enable = true;
diff --git a/common/laptop.nix b/common/laptop.nix
index 2e0d6da..a18c765 100644
--- a/common/laptop.nix
+++ b/common/laptop.nix
@@ -7,11 +7,12 @@
 
 let
   inherit (lib) mkIf mkEnableOption;
+  cfg = config.patagia.podman;
 in
 {
   options.patagia.laptop.enable = mkEnableOption "Laptop tools and configuration";
 
-  config = mkIf config.patagia.laptop.enable {
+  config = mkIf cfg.enable {
     environment.systemPackages = with pkgs; [ gnomeExtensions.battery-health-charging ];
 
     services.fprintd.enable = true;
diff --git a/common/nix.nix b/common/nix.nix
index da49b67..1d2bde9 100644
--- a/common/nix.nix
+++ b/common/nix.nix
@@ -20,7 +20,8 @@
         # Workaround for https://github.com/NixOS/nix/issues/9574
         nix-path = config.nix.nixPath;
         substituters = [
-          "https://cache-nixos-org.aarn.patagia.net/"
+          # "https://cache-nixos-org.aarn.shelman.io"
+          "https://cache.nixos.org/"
         ];
         trusted-public-keys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ];
         extra-substituters = [
diff --git a/files/config/fish/config.fish b/files/config/fish/config.fish
index 4bb823b..e794e56 100644
--- a/files/config/fish/config.fish
+++ b/files/config/fish/config.fish
@@ -12,7 +12,7 @@ set fish_emoji_width 2
 # Colors
 set fish_color_command --bold
 set fish_color_comment --italics --dim
-set fish_color_autosuggestion 1f67f9 --italics --bold
+set fish_color_autosuggestion --italics --bold red
 set fish_color_cancel
 set fish_color_command --bold
 set fish_color_comment --italics --dim
@@ -36,7 +36,7 @@ set fish_color_redirection
 set fish_color_search_match -r
 set fish_color_selection -r
 set fish_color_status normal
-set fish_color_string normal
+set fish_color_string --italics
 set fish_color_user normal
 set fish_color_valid_path
 set fish_pager_color_background
diff --git a/files/config/fish/go-task.fish b/files/config/fish/go-task.fish
new file mode 100644
index 0000000..6c7e2cf
--- /dev/null
+++ b/files/config/fish/go-task.fish
@@ -0,0 +1,37 @@
+set GO_TASK_PROGNAME task
+
+function __task_get_tasks --description "Prints all available tasks with their description"
+    # Read the list of tasks (and potential errors)
+    $GO_TASK_PROGNAME --list-all 2>&1 | read -lz rawOutput
+
+    # Return on non-zero exit code (for cases when there is no Taskfile found or etc.)
+    if test $status -ne 0
+        return
+    end
+
+    # Grab names and descriptions (if any) of the tasks
+    set -l output (echo $rawOutput | sed -e '1d; s/\* \(.*\):\s*\(.*\)\s*(aliases.*/\1\t\2/' -e 's/\* \(.*\):\s*\(.*\)/\1\t\2/'| string split0)
+    if test $output
+        echo $output
+    end
+end
+
+complete -c $GO_TASK_PROGNAME -d 'Runs the specified task(s). Falls back to the "default" task if no task name was specified, or lists all tasks if an unknown task name was
+    specified.' -xa "(__task_get_tasks)"
+
+complete -c $GO_TASK_PROGNAME -s c -l color -d 'colored output (default true)'
+complete -c $GO_TASK_PROGNAME -s d -l dir -d 'sets directory of execution'
+complete -c $GO_TASK_PROGNAME -l dry -d 'compiles and prints tasks in the order that they would be run, without executing them'
+complete -c $GO_TASK_PROGNAME -s f -l force -d 'forces execution even when the task is up-to-date'
+complete -c $GO_TASK_PROGNAME -s h -l help -d 'shows Task usage'
+complete -c $GO_TASK_PROGNAME -s i -l init -d 'creates a new Taskfile.yml in the current folder'
+complete -c $GO_TASK_PROGNAME -s l -l list -d 'lists tasks with description of current Taskfile'
+complete -c $GO_TASK_PROGNAME -s o -l output -d 'sets output style: [interleaved|group|prefixed]' -xa "interleaved group prefixed"
+complete -c $GO_TASK_PROGNAME -s p -l parallel -d 'executes tasks provided on command line in parallel'
+complete -c $GO_TASK_PROGNAME -s s -l silent -d 'disables echoing'
+complete -c $GO_TASK_PROGNAME -l status -d 'exits with non-zero exit code if any of the given tasks is not up-to-date'
+complete -c $GO_TASK_PROGNAME -l summary -d 'show summary about a task'
+complete -c $GO_TASK_PROGNAME -s t -l taskfile -d 'choose which Taskfile to run. Defaults to "Taskfile.yml"'
+complete -c $GO_TASK_PROGNAME -s v -l verbose -d 'enables verbose mode'
+complete -c $GO_TASK_PROGNAME -l version -d 'show Task version'
+complete -c $GO_TASK_PROGNAME -s w -l watch -d 'enables watch of the given task'
diff --git a/files/config/fish/jj.fish b/files/config/fish/jj.fish
new file mode 100644
index 0000000..9a6257e
--- /dev/null
+++ b/files/config/fish/jj.fish
@@ -0,0 +1,338 @@
+# TODO: passthru other args? E.g.. --at-operation, --repository
+function __jj
+    command jj --ignore-working-copy --color=never --quiet $argv 2>/dev/null
+end
+
+# Aliases
+# Based on https://github.com/fish-shell/fish-shell/blob/cd71359c42f633d9d71a63591ae16d150407a2b2/share/completions/git.fish#L625.
+#
+# Aliases are stored in global variables.
+# `__jj_aliases` is a list of all aliases and `__jj_alias_$alias` is the command line for the alias.
+function __jj_add_alias
+    set -l alias $argv[1]
+    set -l alias_escaped (string escape --style=var -- $alias)
+    set -g __jj_alias_$alias_escaped $argv
+    set --append -g __jj_aliases $alias
+end
+
+__jj config list aliases -T 'concat(name, "\t", value, "\n")' --include-defaults | while read -l config_alias
+    set -l parsed (string match --regex '^aliases\.(.+)\t(.*)$' --groups-only -- $config_alias)
+    set -l alias $parsed[1]
+    set -l command $parsed[2]
+    set -l args $alias
+    # Replace wrapping `[]` if any
+    set -l command (string replace -r --all '^\[|]$' ""  -- $command)
+    while test (string length -- $command) -gt 0
+        set -l parsed (string match -r '^"((?:\\\"|[^"])*?)"(?:,\s)?(.*)$' --groups-only  -- $command)
+        set --append args $parsed[1]
+        set command $parsed[2]
+    end
+    __jj_add_alias $args
+end
+
+__jj_add_alias ci commit
+__jj_add_alias desc describe
+__jj_add_alias op operation
+__jj_add_alias st status
+
+# Resolve aliases that call another alias.
+for alias in $__jj_aliases
+    set -l handled $alias
+
+    while true
+        set -l alias_escaped (string escape --style=var -- $alias)
+        set -l alias_varname __jj_alias_$alias_escaped
+        set -l aliased_command $$alias_varname[1][2]
+        set -l aliased_escaped (string escape --style=var -- $aliased_command)
+        set -l aliased_varname __jj_alias_$aliased_escaped
+        set -q $aliased_varname
+        or break
+
+        # Prevent infinite recursion
+        contains $aliased_escaped $handled
+        and break
+
+        # Expand alias in cmdline
+        set -l aliased_cmdline $$aliased_varname[1][2..-1]
+        set --append aliased_cmdline $$alias_varname[1][3..-1]
+        set -g $alias_varname $$alias_varname[1][1] $aliased_cmdline
+        set --append handled $aliased_escaped
+    end
+end
+
+function __jj_aliases_with_descriptions
+    for alias in $__jj_aliases
+        set -l alias_escaped (string escape --style=var -- $alias)
+        set -l alias_varname __jj_alias_$alias_escaped
+        set -l aliased_cmdline (string join " " -- $$alias_varname[1][2..-1] | string replace -r --all '\\\"' '"')
+        printf "%s\talias: %s\n" $alias $aliased_cmdline
+    end
+end
+
+# Based on https://github.com/fish-shell/fish-shell/blob/2d4e42ee93327b9cfd554a0d809f85e3d371e70e/share/functions/__fish_seen_subcommand_from.fish.
+# Test to see if we've seen a subcommand from a list.
+# This logic may seem backwards, but the commandline will often be much shorter than the list.
+function __jj_seen_subcommand_from
+    set -l cmd (commandline -opc)
+    set -e cmd[1]
+
+    # Check command line arguments first.
+    for i in $cmd
+        if contains -- $i $argv
+            return 0
+        end
+    end
+
+    # Check aliases.
+    set -l alias $cmd[1]
+    set -l alias_escaped (string escape --style=var -- $alias)
+    set -l varname __jj_alias_$alias_escaped
+    set -q $varname
+    or return 1
+
+    for i in $$varname[1][2..-1]
+        if contains -- $i $argv
+            return 0
+        end
+    end
+
+    return 1
+end
+
+function __jj_changes
+    __jj log --no-graph --limit 1000 -r $argv[1] \
+        -T 'separate("\t", change_id.shortest(), if(description, description.first_line(), "(no description set)")) ++ "\n"'
+end
+
+function __jj_bookmarks
+    set -f filter $argv[1]
+    if string length --quiet -- $argv[2]
+        __jj bookmark list --all-remotes -r "$argv[2]" \
+            -T "if($filter, name ++ if(remote, \"@\" ++ remote) ++ \"\t\" ++ if(normal_target, normal_target.change_id().shortest() ++ \": \" ++ if(normal_target.description(), normal_target.description().first_line(), \"(no description set)\"), \"(conflicted bookmark)\") ++ \"\n\")"
+    else
+        __jj bookmark list --all-remotes \
+            -T "if($filter, name ++ if(remote, \"@\" ++ remote) ++ \"\t\" ++ if(normal_target, normal_target.change_id().shortest() ++ \": \" ++ if(normal_target.description(), normal_target.description().first_line(), \"(no description set)\"), \"(conflicted bookmark)\") ++ \"\n\")"
+    end
+end
+
+function __jj_all_bookmarks
+    __jj_bookmarks '!remote || !remote.starts_with("git")' $argv[1]
+end
+
+function __jj_local_bookmarks
+    __jj_bookmarks '!remote' ''
+end
+
+function __jj_remote_bookmarks
+    __jj_bookmarks 'remote && !remote.starts_with("git")' ''
+end
+
+function __jj_all_changes
+    if string length --quiet -- $argv[1]
+        set -f REV $argv[1]
+    else
+        set -f REV "all()"
+    end
+    __jj_changes $REV
+    __jj_all_bookmarks $REV
+end
+
+function __jj_mutable_changes
+    set -f REV "mutable()"
+    __jj_changes $REV
+    __jj_all_bookmarks $REV
+end
+
+function __jj_revision_modified_files
+    if test $argv[1] = "@"
+        set -f suffix ""
+    else
+        set -l change_id (__jj log --no-graph --limit 1 -T 'change_id.shortest()')
+        set -f suffix " in $change_id"
+    end
+
+    __jj diff -r $argv[1] --summary | while read -l line
+        set -l file (string split " " -m 1 -- $line)
+        switch $file[1]
+            case M
+                set -f change Modified
+            case D
+                set -f change Deleted
+            case A
+                set -f change Added
+        end
+        printf "%s\t%s%s\n" $file[2] $change $suffix
+    end
+end
+
+function __jj_remotes
+    __jj git remote list | while read -l remote
+        printf "%s\t%s\n" (string split " " -m 1 -- $remote)
+    end
+end
+
+function __jj_operations
+    __jj operation log --no-graph --limit 1000 -T 'separate("\t", id.short(), description) ++ "\n"'
+end
+
+function __jj_parse_revision
+    set -l cmd (commandline -opc)
+    set -e cmd[1]
+    set -l return_next false
+    set -l return_value 1
+
+    # Check aliases.
+    set -l alias $cmd[1]
+    set -l alias_escaped (string escape --style=var -- $alias)
+    set -l varname __jj_alias_$alias_escaped
+
+    if set -q $varname
+        set cmd $$varname[1][2..-1] $cmd[2..-1]
+    end
+
+    # Check command line arguments first.
+    for i in $cmd
+        if $return_next
+            echo $i
+            set return_value 0
+        else if contains -- $i -r --revision --from
+            set return_next true
+        else
+            set -l match (string match --regex '^(?:-r=?|--revision=|--from=)(.+)\s*$' --groups-only -- $i)
+            if set -q match[1]
+                echo $match[1]
+                set return_value 0
+            end
+        end
+    end
+
+    return $return_value
+end
+
+function __jj_revision_files
+    set -l description (__jj log --no-graph --limit 1 -r $argv[1] -T 'change_id.shortest() ++ ": " ++ coalesce(description.first_line().substr(0, 30), "(no description set)")')
+    __jj file list -r $argv[1] | while read -l file
+        printf "%s\t%s\n" $file $description
+    end
+end
+
+function __jj_revision_conflicted_files
+    __jj resolve --list -r $argv[1] | while read -l line
+        set -l file (string split " " -m 1 -- $line)
+        printf "%s\t%s\n" $file[1] $file[2]
+    end
+end
+
+function __jj_parse_revision_files
+    set -l rev (__jj_parse_revision)
+    if test $status -eq 1
+        set rev "@"
+    end
+    __jj_revision_files $rev
+end
+
+function __jj_parse_revision_conflicted_files
+    set -l rev (__jj_parse_revision)
+    if test $status -eq 1
+        set rev "@"
+    end
+    __jj_revision_conflicted_files $rev
+end
+
+function __jj_parse_revision_files_or_wc_modified_files
+    set -l revs (__jj_parse_revision)
+    if test $status -eq 1
+        __jj_revision_modified_files "@"
+    else
+        for rev in $revs
+            __jj_revision_files $rev
+        end
+    end
+end
+
+function __jj_parse_revision_modified_files_or_wc_modified_files
+    set -l revs (__jj_parse_revision)
+    if test $status -eq 1
+        __jj_revision_modified_files "@"
+    else
+        for rev in $revs
+            __jj_revision_modified_files $rev
+        end
+    end
+end
+
+# Aliases.
+complete -f -c jj -n __fish_use_subcommand -a '(__jj_aliases_with_descriptions)'
+
+# Files.
+complete -f -c jj -n '__jj_seen_subcommand_from file; and __jj_seen_subcommand_from show' -ka '(__jj_parse_revision_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from file; and __jj_seen_subcommand_from chmod' -ka '(__jj_parse_revision_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from commit' -ka '(__jj_revision_modified_files "@")'
+complete -c jj -n '__jj_seen_subcommand_from diff' -ka '(__jj_parse_revision_files_or_wc_modified_files)'
+complete -c jj -n '__jj_seen_subcommand_from interdiff' -ka '(__jj_parse_revision_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from resolve' -ka '(__jj_parse_revision_conflicted_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from restore' -ka '(__jj_parse_revision_files_or_wc_modified_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from split' -ka '(__jj_parse_revision_modified_files_or_wc_modified_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from squash' -ka '(__jj_parse_revision_modified_files_or_wc_modified_files)'
+complete -f -c jj -n '__jj_seen_subcommand_from untrack' -ka '(__jj_parse_revision_files_or_wc_modified_files)'
+
+# Revisions.
+complete -f -c jj -n '__jj_seen_subcommand_from abandon' -ka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from backout' -s r -l revision -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from backout' -s d -l destination -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from file; and __jj_seen_subcommand_from show' -s r -l revision -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from chmod' -s r -l revision -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from describe' -ka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diff' -s r -l revision -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diff' -l from -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diff' -l to -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diffedit' -s r -l revision -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diffedit' -l from -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from diffedit' -l to -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from duplicate' -ka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from edit' -ka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from file; and __jj_seen_subcommand_from list' -s r -l revision -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from interdiff' -l from -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from interdiff' -l to -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from log' -s r -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from new' -ka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from new' -s A -l after -l insert-after -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from new' -s B -l before -l insert-before -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from obslog' -s r -l revision -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from parallelize' -ka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s r -l revisions -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s s -l source -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s b -l bookmark -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s d -l destination -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s A -l after -l insert-after -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from rebase' -s B -l before -l insert-before -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from resolve' -s r -l revision -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from restore' -l from -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from restore' -l to -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from restore' -s c -l changes-in -rka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from show' -ka '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from split' -s r -l revision -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from squash' -s r -l revision -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from squash' -l from -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from squash' -l to -l into -rka '(__jj_mutable_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from unsquash' -s r -l revision -rka '(__jj_mutable_changes)'
+
+# Bookmarks
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from delete forget rename set d f r s' -ka '(__jj_local_bookmarks)'
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from track t' -ka '(__jj_bookmarks "remote && !tracked" "")'
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from untrack' -ka '(__jj_bookmarks "remote && tracked && !remote.starts_with(\"git\")" "")'
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from create move set c m s' -s r -l revision -kra '(__jj_all_changes)'
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from move' -l from -rka '(__jj_changes "all()")'
+complete -f -c jj -n '__jj_seen_subcommand_from bookmark; and __jj_seen_subcommand_from move' -l to -rka '(__jj_changes "all()")'
+
+# Git.
+complete -f -c jj -n '__jj_seen_subcommand_from git; and __jj_seen_subcommand_from push' -s c -l change -kra '(__jj_changes "all()")'
+complete -f -c jj -n '__jj_seen_subcommand_from git; and __jj_seen_subcommand_from push' -s r -l revisions -kra '(__jj_changes "all()")'
+complete -f -c jj -n '__jj_seen_subcommand_from git; and __jj_seen_subcommand_from fetch push' -s b -l bookmark -rka '(__jj_local_bookmarks)'
+complete -f -c jj -n '__jj_seen_subcommand_from git; and __jj_seen_subcommand_from fetch push' -l remote -rka '(__jj_remotes)'
+complete -f -c jj -n '__jj_seen_subcommand_from git; and __jj_seen_subcommand_from remote; and __jj_seen_subcommand_from remove rename set-url' -ka '(__jj_remotes)'
+
+# Operations.
+complete -f -c jj -l at-op -l at-operation -rka '(__jj_operations)'
+complete -f -c jj -n '__jj_seen_subcommand_from undo' -ka '(__jj_operations)'
+complete -f -c jj -n '__jj_seen_subcommand_from operation; and __jj_seen_subcommand_from abandon undo restore' -ka '(__jj_operations)'
diff --git a/files/config/fish/vcs.fish b/files/config/fish/vcs.fish
index 0fa3e43..4859d3b 100644
--- a/files/config/fish/vcs.fish
+++ b/files/config/fish/vcs.fish
@@ -53,6 +53,15 @@ function vcs_log
     commandline -f repaint
 end
 
+function vcs_ui
+    if __jj_in_repo
+        lazyjj
+    else
+        gitui
+    end
+    commandline -f repaint
+end
+
 # Abbreviations
 
 abbr -a d vcs_diff
@@ -62,9 +71,6 @@ abbr -a s vcs_status
 bind \c_ vcs_jump
 bind \ea vcs_log
 bind \ee vcs_broot
+bind \eg vcs_ui
 bind \eS vcs_diff
 bind \es vcs_status
-
-# jj completions
-
-COMPLETE=fish jj | source
diff --git a/files/scripts/test-term.sh b/files/scripts/test-term.sh
index e702886..822e174 100755
--- a/files/scripts/test-term.sh
+++ b/files/scripts/test-term.sh
@@ -186,109 +186,3 @@ for i in $(seq 255 -1 128); do
 	echo -n " "
 done
 resetOutput
-
-
-## Color test
-
-# Tom Hale, 2016. MIT Licence.
-# Print out 256 colours, with each number printed in its corresponding colour
-# See http://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal/821163#821163
-
-set -eu # Fail on errors or undeclared variables
-
-printable_colours=256
-
-# Return a colour that contrasts with the given colour
-# Bash only does integer division, so keep it integral
-function contrast_colour {
-    local r g b luminance
-    colour="$1"
-
-    if (( colour < 16 )); then # Initial 16 ANSI colours
-        (( colour == 0 )) && printf "15" || printf "0"
-        return
-    fi
-
-    # Greyscale # rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8
-    if (( colour > 231 )); then # Greyscale ramp
-        (( colour < 244 )) && printf "15" || printf "0"
-        return
-    fi
-
-    # All other colours:
-    # 6x6x6 colour cube = 16 + 36*R + 6*G + B  # Where RGB are [0..5]
-    # See http://stackoverflow.com/a/27165165/5353461
-
-    # r=$(( (colour-16) / 36 ))
-    g=$(( ((colour-16) % 36) / 6 ))
-    # b=$(( (colour-16) % 6 ))
-
-    # If luminance is bright, print number in black, white otherwise.
-    # Green contributes 587/1000 to human perceived luminance - ITU R-REC-BT.601
-    (( g > 2)) && printf "0" || printf "15"
-    return
-
-    # Uncomment the below for more precise luminance calculations
-
-    # # Calculate percieved brightness
-    # # See https://www.w3.org/TR/AERT#color-contrast
-    # # and http://www.itu.int/rec/R-REC-BT.601
-    # # Luminance is in range 0..5000 as each value is 0..5
-    # luminance=$(( (r * 299) + (g * 587) + (b * 114) ))
-    # (( $luminance > 2500 )) && printf "0" || printf "15"
-}
-
-# Print a coloured block with the number of that colour
-function print_colour {
-    local colour="$1" contrast
-    contrast=$(contrast_colour "$1")
-    printf "\e[48;5;%sm" "$colour"                # Start block of colour
-    printf "\e[38;5;%sm%3d" "$contrast" "$colour" # In contrast, print number
-    printf "\e[0m "                               # Reset colour
-}
-
-# Starting at $1, print a run of $2 colours
-function print_run {
-    local i
-    for (( i = "$1"; i < "$1" + "$2" && i < printable_colours; i++ )) do
-        print_colour "$i"
-    done
-    printf "  "
-}
-
-# Print blocks of colours
-function print_blocks {
-    local start="$1" i
-    local end="$2" # inclusive
-    local block_cols="$3"
-    local block_rows="$4"
-    local blocks_per_line="$5"
-    local block_length=$((block_cols * block_rows))
-
-    # Print sets of blocks
-    for (( i = start; i <= end; i += (blocks_per_line-1) * block_length )) do
-        printf "\n" # Space before each set of blocks
-        # For each block row
-        for (( row = 0; row < block_rows; row++ )) do
-            # Print block columns for all blocks on the line
-            for (( block = 0; block < blocks_per_line; block++ )) do
-                print_run $(( i + (block * block_length) )) "$block_cols"
-            done
-            (( i += block_cols )) # Prepare to print the next row
-            printf "\n"
-        done
-    done
-}
-
-echo
-echo "ANSI 4-bit colors:"
-echo
-
-print_run 0 16 # The first 16 colours are spread over the whole spectrum
-
-echo
-echo
-echo "ANSI 8-bit colors:"
-
-print_blocks 16 231 6 6 3 # 6x6x6 colour cube between 16 and 231 inclusive
-print_blocks 232 255 12 2 1 # Not 50, but 24 Shades of Grey
diff --git a/flake.lock b/flake.lock
index 3157c71..79dd621 100644
--- a/flake.lock
+++ b/flake.lock
@@ -3,11 +3,11 @@
     "flake-compat": {
       "flake": false,
       "locked": {
-        "lastModified": 1747046372,
-        "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
+        "lastModified": 1696426674,
+        "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
         "owner": "edolstra",
         "repo": "flake-compat",
-        "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
+        "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
         "type": "github"
       },
       "original": {
@@ -40,11 +40,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743550720,
-        "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
+        "lastModified": 1730504689,
+        "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "c621e8422220273271f52058f618c94e405bb0f5",
+        "rev": "506278e768c2a08bec68eb62932193e341f55c90",
         "type": "github"
       },
       "original": {
@@ -62,11 +62,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743550720,
-        "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
+        "lastModified": 1712014858,
+        "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "c621e8422220273271f52058f618c94e405bb0f5",
+        "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
         "type": "github"
       },
       "original": {
@@ -74,6 +74,63 @@
         "type": "indirect"
       }
     },
+    "flake-utils": {
+      "inputs": {
+        "systems": "systems"
+      },
+      "locked": {
+        "lastModified": 1705309234,
+        "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "ghostty": {
+      "inputs": {
+        "nixpkgs-stable": [
+          "nixpkgs"
+        ],
+        "nixpkgs-unstable": [
+          "nixpkgs"
+        ],
+        "zig": "zig"
+      },
+      "locked": {
+        "lastModified": 1731971697,
+        "narHash": "sha256-6JNMcpy0z19yOLBRt3eE4Rk4A96kcEsRv5+ym1hkv1c=",
+        "ref": "refs/heads/main",
+        "rev": "29c3a52e964a97dddaed876ce472aeb167774acf",
+        "revCount": 8021,
+        "type": "git",
+        "url": "ssh://git@github.com/ghostty-org/ghostty"
+      },
+      "original": {
+        "type": "git",
+        "url": "ssh://git@github.com/ghostty-org/ghostty"
+      }
+    },
+    "ghostty-hm": {
+      "locked": {
+        "lastModified": 1702368251,
+        "narHash": "sha256-hafrDmzGplzm+vdIo+LkOjRfA4qRcy5JmpGGksnht5c=",
+        "owner": "clo4",
+        "repo": "ghostty-hm-module",
+        "rev": "887e13a6e7acf5ffaab0119d96e476d84db90904",
+        "type": "github"
+      },
+      "original": {
+        "owner": "clo4",
+        "repo": "ghostty-hm-module",
+        "type": "github"
+      }
+    },
     "git-hooks": {
       "inputs": {
         "flake-compat": "flake-compat_2",
@@ -81,14 +138,18 @@
         "nixpkgs": [
           "neovim-nightly-overlay",
           "nixpkgs"
+        ],
+        "nixpkgs-stable": [
+          "neovim-nightly-overlay",
+          "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1747372754,
-        "narHash": "sha256-2Y53NGIX2vxfie1rOW0Qb86vjRZ7ngizoo+bnXU9D9k=",
+        "lastModified": 1731363552,
+        "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=",
         "owner": "cachix",
         "repo": "git-hooks.nix",
-        "rev": "80479b6ec16fefd9c1db3ea13aeb038c60530f46",
+        "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0",
         "type": "github"
       },
       "original": {
@@ -128,11 +189,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1748000383,
-        "narHash": "sha256-EaAJhwfJGBncgIV/0NlJviid2DP93cTMc9h0q6P6xXk=",
+        "lastModified": 1730903510,
+        "narHash": "sha256-mnynlrPeiW0nUQ8KGZHb3WyxAxA3Ye/BH8gMjdoKP6E=",
         "owner": "hercules-ci",
         "repo": "hercules-ci-effects",
-        "rev": "231726642197817d20310b9d39dd4afb9e899489",
+        "rev": "b89ac4d66d618b915b1f0a408e2775fe3821d141",
         "type": "github"
       },
       "original": {
@@ -148,11 +209,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1748570847,
-        "narHash": "sha256-XU1a6wFctd+s3ZvBIFB6s4GhPJ+Oc6pkeOrEsbA2fMo=",
+        "lastModified": 1731968878,
+        "narHash": "sha256-+hTCwETOE9N8voTAaF+IzdUZz28Ws3LDpH90FWADrEE=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "4e9efaa68b0be7e19127dad4f0506a9b89e28ef4",
+        "rev": "a42fa14b53ceab66274a21da480c9f8e06204173",
         "type": "github"
       },
       "original": {
@@ -168,15 +229,14 @@
         "git-hooks": "git-hooks",
         "hercules-ci-effects": "hercules-ci-effects",
         "neovim-src": "neovim-src",
-        "nixpkgs": "nixpkgs",
-        "treefmt-nix": "treefmt-nix"
+        "nixpkgs": "nixpkgs"
       },
       "locked": {
-        "lastModified": 1748588826,
-        "narHash": "sha256-lfSvGRDpep7LVD4L/97Xjn3bglB247S4bgpfpMbqGP4=",
+        "lastModified": 1732002290,
+        "narHash": "sha256-v17KxlCf0O7hoD9AjiF94T2nuZuh7ZREyI6Ww/Tr4R0=",
         "owner": "nix-community",
         "repo": "neovim-nightly-overlay",
-        "rev": "2e9ad466d7b54245229087c980da0615f54e4b2f",
+        "rev": "2a9b9e821c7f91eb6ae540925a453f9ebacd0513",
         "type": "github"
       },
       "original": {
@@ -188,11 +248,11 @@
     "neovim-src": {
       "flake": false,
       "locked": {
-        "lastModified": 1748543356,
-        "narHash": "sha256-Xo3LBLzEMIdmT0s8UWfNUJvTBHxB5PSYKJyFPBcGx8w=",
+        "lastModified": 1731949793,
+        "narHash": "sha256-ZXZInL8J38JaVpglSPa78ptn1zlqbaRHDtpa73CqpfI=",
         "owner": "neovim",
         "repo": "neovim",
-        "rev": "b28bbee539625f9bcbf128e8da400d1d55b499ff",
+        "rev": "989a37a594649528f28432388c0e7e28e8be2753",
         "type": "github"
       },
       "original": {
@@ -201,33 +261,13 @@
         "type": "github"
       }
     },
-    "nix-index-database": {
-      "inputs": {
-        "nixpkgs": [
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1748145500,
-        "narHash": "sha256-t9fx0l61WOxtWxXCqlXPWSuG/0XMF9DtE2T7KXgMqJw=",
-        "owner": "nix-community",
-        "repo": "nix-index-database",
-        "rev": "a98adbf54d663395df0b9929f6481d4d80fc8927",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "nix-index-database",
-        "type": "github"
-      }
-    },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1748475218,
-        "narHash": "sha256-zDYqMBDbQR4SU9vHFrvHRbI0qxv0RGAoog5idGLiOWQ=",
+        "lastModified": 1731890469,
+        "narHash": "sha256-D1FNZ70NmQEwNxpSSdTXCSklBH1z2isPR84J6DQrJGs=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "e80506de785dc48dcfbb636c443c5e2b0b5b2d7d",
+        "rev": "5083ec887760adfe12af64830a66807423a859a7",
         "type": "github"
       },
       "original": {
@@ -239,27 +279,27 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1748437600,
-        "narHash": "sha256-hYKMs3ilp09anGO7xzfGs3JqEgUqFMnZ8GMAqI6/k04=",
+        "lastModified": 1731797254,
+        "narHash": "sha256-df3dJApLPhd11AlueuoN0Q4fHo/hagP75LlM5K1sz9g=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "7282cb574e0607e65224d33be8241eae7cfe0979",
+        "rev": "e8c38b73aeb218e27163376a2d617e61a2ad9b59",
         "type": "github"
       },
       "original": {
         "owner": "nixos",
-        "ref": "nixos-25.05",
+        "ref": "nixos-24.05",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs-unstable": {
       "locked": {
-        "lastModified": 1748506378,
-        "narHash": "sha256-oS0Gxh63Df8b8r04lqEYDDLKhHIrVr9/JLOn2bn8JaI=",
+        "lastModified": 1731890469,
+        "narHash": "sha256-D1FNZ70NmQEwNxpSSdTXCSklBH1z2isPR84J6DQrJGs=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "3866ad91cfc172f08a6839def503d8fc2923c603",
+        "rev": "5083ec887760adfe12af64830a66807423a859a7",
         "type": "github"
       },
       "original": {
@@ -271,11 +311,11 @@
     },
     "nixpkgs_2": {
       "locked": {
-        "lastModified": 1748370509,
-        "narHash": "sha256-QlL8slIgc16W5UaI3w7xHQEP+Qmv/6vSNTpoZrrSlbk=",
+        "lastModified": 1731676054,
+        "narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "4faa5f5321320e49a78ae7848582f684d64783e9",
+        "rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
         "type": "github"
       },
       "original": {
@@ -287,32 +327,52 @@
     },
     "root": {
       "inputs": {
+        "ghostty": "ghostty",
+        "ghostty-hm": "ghostty-hm",
         "home-manager": "home-manager",
         "neovim-nightly-overlay": "neovim-nightly-overlay",
-        "nix-index-database": "nix-index-database",
         "nixpkgs": "nixpkgs_2",
         "nixpkgs-stable": "nixpkgs-stable",
         "nixpkgs-unstable": "nixpkgs-unstable"
       }
     },
-    "treefmt-nix": {
-      "inputs": {
-        "nixpkgs": [
-          "neovim-nightly-overlay",
-          "nixpkgs"
-        ]
-      },
+    "systems": {
       "locked": {
-        "lastModified": 1748243702,
-        "narHash": "sha256-9YzfeN8CB6SzNPyPm2XjRRqSixDopTapaRsnTpXUEY8=",
-        "owner": "numtide",
-        "repo": "treefmt-nix",
-        "rev": "1f3f7b784643d488ba4bf315638b2b0a4c5fb007",
+        "lastModified": 1681028828,
+        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+        "owner": "nix-systems",
+        "repo": "default",
+        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
         "type": "github"
       },
       "original": {
-        "owner": "numtide",
-        "repo": "treefmt-nix",
+        "owner": "nix-systems",
+        "repo": "default",
+        "type": "github"
+      }
+    },
+    "zig": {
+      "inputs": {
+        "flake-compat": [
+          "ghostty"
+        ],
+        "flake-utils": "flake-utils",
+        "nixpkgs": [
+          "ghostty",
+          "nixpkgs-stable"
+        ]
+      },
+      "locked": {
+        "lastModified": 1717848532,
+        "narHash": "sha256-d+xIUvSTreHl8pAmU1fnmkfDTGQYCn2Rb/zOwByxS2M=",
+        "owner": "mitchellh",
+        "repo": "zig-overlay",
+        "rev": "02fc5cc555fc14fda40c42d7c3250efa43812b43",
+        "type": "github"
+      },
+      "original": {
+        "owner": "mitchellh",
+        "repo": "zig-overlay",
         "type": "github"
       }
     }
diff --git a/flake.nix b/flake.nix
index fd4ba17..848f99f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -3,7 +3,7 @@
 
   nixConfig = {
     substituters = [
-      "https://cache-nixos-org.aarn.patagia.net/"
+      "https://cache.nixos.org/"
     ];
     extra-substituters = [
       "https://nix-community.cachix.org"
@@ -15,23 +15,28 @@
 
   inputs = {
     neovim-nightly-overlay.url = "github:nix-community/neovim-nightly-overlay";
-    nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
-    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
     nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
-
-    nix-index-database.url = "github:nix-community/nix-index-database";
-    nix-index-database.inputs.nixpkgs.follows = "nixpkgs";
+    nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-24.05";
+    nixpkgs-unstable.url = "github:nixos/nixpkgs/nixpkgs-unstable";
 
     home-manager.url = "github:nix-community/home-manager";
     home-manager.inputs.nixpkgs.follows = "nixpkgs";
+
+    ghostty = {
+      url = "git+ssh://git@github.com/ghostty-org/ghostty";
+      inputs = {
+        nixpkgs-stable.follows = "nixpkgs";
+        nixpkgs-unstable.follows = "nixpkgs";
+      };
+    };
+    ghostty-hm.url = "github:clo4/ghostty-hm-module";
   };
 
   outputs =
     inputs@{
       self,
-      nix-index-database,
       nixpkgs,
-      nixpkgs-unstable,
+      ghostty-hm,
       home-manager,
       ...
     }:
@@ -52,13 +57,13 @@
       mkHome =
         modules:
         home-manager.lib.homeManagerConfiguration {
-          pkgs = nixpkgs-unstable.legacyPackages.${system};
+          inherit pkgs;
           extraSpecialArgs = {
             inherit inputs outputs;
           };
           modules = [
+            ghostty-hm.homeModules.default
             ./home/common
-            nix-index-database.hmModules.nix-index
           ] ++ modules;
         };
     in
@@ -68,11 +73,7 @@
       devShell.${system} = pkgs.mkShell {
         packages = with pkgs; [
           just
-          lua-language-server
           nh
-          nil
-          nixd
-          nixfmt-rfc-style
         ];
       };
 
@@ -86,6 +87,7 @@
         "dln@dinky" = mkHome [ ./home/dln/dinky.nix ];
         "dln@nemo" = mkHome [ ./home/dln/nemo.nix ];
         "dln@pearl" = mkHome [ ./home/dln/pearl.nix ];
+        "lsjostro@nemo" = mkHome [ ./home/lsjostro/nemo.nix ];
       };
     };
 }
diff --git a/home/common/atuin.nix b/home/common/atuin.nix
index 991dcec..720459b 100644
--- a/home/common/atuin.nix
+++ b/home/common/atuin.nix
@@ -13,7 +13,7 @@
       search_mode_shell_up_key_binding = "prefix";
       show_help = false;
       style = "compact";
-      sync_address = "https://atuin.patagia.net";
+      sync_address = "https://atuin.patagia.dev";
       sync.records = true;
 
       daemon = {
diff --git a/home/common/default.nix b/home/common/default.nix
index c5112bd..3a2a686 100644
--- a/home/common/default.nix
+++ b/home/common/default.nix
@@ -16,10 +16,7 @@
     ./utils.nix
     ./vcs.nix
     ./web.nix
-    ./wezterm.nix
   ];
 
   options.patagia.desktop.enable = lib.mkEnableOption "Desktop environment";
-  options.patagia.laptop.enable = lib.mkEnableOption "Laptop";
-  options.patagia.oled.enable = lib.mkEnableOption "Darker darks on oled screens";
 }
diff --git a/home/common/devel.nix b/home/common/devel.nix
index 70c3bcc..c8e6c0a 100644
--- a/home/common/devel.nix
+++ b/home/common/devel.nix
@@ -2,17 +2,33 @@
 {
   home.packages = with pkgs; [
     age-plugin-fido2-hmac
+    bacon
+    cargo
+    clang
+    codeium
     comma
     dogdns
     file
+    gnumake
+    go
     just
+    ldns
+    minio-client
+    nil
     nix-output-monitor
-    openssl
+    nixd
+    nixfmt-rfc-style
+    nodejs_22
     passage
     rage
+    prettierd
+    rust-analyzer
+    rustc
+    stylua
+    tree-sitter
   ];
 
   home.sessionVariables = {
-    GOPROXY = "https://athena.patagia.net";
+    GOPROXY = "https://athena.patagia.dev";
   };
 }
diff --git a/home/common/fish.nix b/home/common/fish.nix
index e5d1c45..44678fa 100644
--- a/home/common/fish.nix
+++ b/home/common/fish.nix
@@ -3,7 +3,12 @@
   programs.fish = {
     enable = true;
 
+
     plugins = [
+      {
+        name = "grc";
+        src = pkgs.fishPlugins.grc.src;
+      }
       {
         name = "transient";
         src = pkgs.fishPlugins.transient-fish.src;
@@ -38,11 +43,40 @@
         body = ''confirm "⚠ Really shutdown $(hostname)?" && command shutdown $argv'';
       };
 
-      e = {
-        description = "Open a file in already running nvim";
+      tmux-refresh-env = {
+        description = "Refresh environment variables from tmux session";
+        body = ''
+          for var in (tmux show-environment | string match -rv '^-')
+            set -l parts (string split -m 1 '=' $var)
+            if test (count $parts) -eq 2
+              set -Ux $parts[1] $parts[2]
+            end
+          end
+        '';
+      };
+
+      kubectl = {
+        description = "Wraps kubectl in grc";
+        wraps = "kubectl";
+        body = "grc.wrap kubectl $argv";
+      };
+
+      edit = {
+        description = "Open a file in already running nvim and switch tab";
         argumentNames = [ "file" ];
         body = ''
-          nvim-remote --remote (readlink -f "$file")
+          set _file (readlink -f "$file")
+          if test -z "$file"
+              set _root (vcs_root)
+              set _file (fd --type f . "$_root" | sed -e "s#^$_root/##" | fzf --no-sort --layout=reverse)
+              set _file "$_root/$_file"
+          end
+          set _nvim_socket "$XDG_RUNTIME_DIR/nvim-persistent.sock"
+          if test -S "$_nvim_socket" && tmux select-window -t nvim 2>/dev/null
+            nvim --server "$_nvim_socket" --remote "$_file"
+            return 0
+          end
+          tmux new-window -S -n nvim nvim --listen "$_nvim_socket" "$_file"
         '';
       };
 
@@ -56,32 +90,17 @@
       '';
 
       fish_jj_prompt.body = ''
-          if not command -sq jj || not jj root --quiet &>/dev/null
-            return 1
-          end
+        if not command -sq jj || not jj root --quiet &>/dev/null
+          return 1
+        end
 
+        # Generate prompt
         jj log --ignore-working-copy --no-graph --color never -r @ -T '
           surround(
             " \e[2;3m",
             "\e[0m",
             separate(
               " ",
-              surround(
-                "\e[0;2;3m",
-                "\e[0m",
-                coalesce(
-                  surround(
-                    "\e[1;2;3m❝",
-                    "❞\e[0m",
-                    if(
-                      description.first_line().substr(0, 80).starts_with(description.first_line()),
-                      description.first_line().substr(0, 80),
-                      description.first_line().substr(0, 79) ++ "…"
-                    )
-                  ),
-                  "…"
-                ),
-              ),
               surround("\e[0;1;95m ", "\e[0;2;3m", change_id.shortest()),
               surround("\e[0;35m󰸕 ", "\e[0m", bookmarks.join("╱")),
               surround("\e[0;34m ",   "\e[0;2;3m", commit_id.shortest()),
@@ -94,14 +113,50 @@
         '
       '';
 
+      fish_jj_desc.body = ''
+        if not command -sq jj || not jj root --quiet &>/dev/null
+          return 1
+        end
+
+        jj log --ignore-working-copy --no-graph --color never -r @ -T '
+          surround(
+            " \e[0;2;3m",
+            "\e[0m",
+            coalesce(
+              surround(
+                "\e[1;2;3m❝",
+                "❞\e[0m",
+                if(
+                  description.first_line().substr(0, 80).starts_with(description.first_line()),
+                  description.first_line().substr(0, 80),
+                  description.first_line().substr(0, 79) ++ "…"
+                )
+              ),
+              "…"
+            ),
+          )
+        '
+      '';
+
       fish_prompt.body = ''
-        echo -e "\033[s\033[$LINES;1H\033[1;2;38;5;238m$(string pad -c '┄' -w $COLUMNS (fish_jj_prompt || fish_vcs_prompt))\033[0m\033[u"
-        string join "" -- (set_color --dim) (prompt_hostname) ':' (prompt_pwd --full-length-dirs=4) (set_color --bold normal) ' ❯ ' (set_color normal)
+        echo -e "\033[1;2;38;5;236m"
+        string pad -c '┄' -w $COLUMNS (fish_jj_desc)
+        echo -ne "\033[0;3m"
+        string join "" -- (set_color --italics) (prompt_hostname) ':' (prompt_pwd --full-length-dirs=4) (set_color yellow) ' ❯ ' (set_color normal)
+      '';
+
+      fish_right_prompt.body = ''
+        if test $CMD_DURATION -gt 3000
+          # Show duration of the last command in seconds
+          set duration (echo "$CMD_DURATION 1000" | awk '{printf "%.1fs", $1 / $2}')
+          echo -n "⏳$duration "
+        end
+        fish_jj_prompt || fish_vcs_prompt
       '';
 
       transient_prompt_func.body = ''
         echo
-        string join "" -- (set_color --bold) '❯ ' (set_color normal)
+        string join "" -- (set_color yellow) '❯ ' (set_color normal)
       '';
 
       rg.body = ''
@@ -116,14 +171,19 @@
     interactiveShellInit = lib.concatStringsSep "\n" [
       (builtins.readFile ../../files/config/fish/config.fish)
       (builtins.readFile ../../files/config/fish/semantic-prompt.fish)
+      (builtins.readFile ../../files/config/fish/go-task.fish)
+      (builtins.readFile ../../files/config/fish/jj.fish)
       (builtins.readFile ../../files/config/fish/vcs.fish)
     ];
 
     shellAbbrs = {
+      e = "edit";
       l = "bat";
+      ls = "eza";
+      tree = "eza --tree";
       top = "btm --basic --enable_cache_memory --battery";
       ts = "TZ=Z date '+%Y%m%dT%H%M%SZ'";
-      w = "viddy $history[1]";
+      w = "viddy -n1 $history[1]";
       xc = "fish_clipboard_copy";
     };
   };
diff --git a/home/common/ghostty.nix b/home/common/ghostty.nix
index 8946ddd..caa6992 100644
--- a/home/common/ghostty.nix
+++ b/home/common/ghostty.nix
@@ -1,128 +1,159 @@
 {
   config,
+  inputs,
   lib,
+  pkgs,
   ...
 }:
+let
+  launch-ghostty = pkgs.writeShellApplication {
+    name = "launch-ghostty";
+    text = ''
+      if [ "$(gsettings get org.gnome.desktop.interface color-scheme)" = "'prefer-dark'" ]; then
+        theme="theme_dark"
+      else
+        theme="theme_light"
+      fi
+      exec ghostty --config-file="$HOME/.config/ghostty/$theme" "$@"
+    '';
+  };
+in
 {
   config = lib.mkIf config.patagia.desktop.enable {
+
+    home.packages = with pkgs; [
+      inputs.ghostty.packages.${pkgs.system}.default
+      launch-ghostty
+    ];
+
     programs.ghostty = {
       enable = true;
-      enableFishIntegration = true;
       settings = {
-        font-size = 11;
-        font-family = "Berkeley Mono";
-        font-family-italic = "Monaspace Radon Var";
-        font-family-bold-italic = "Monaspace Krypton Var";
-        font-style = "SemiCondensed";
-        font-style-bold = "ExtraBold SemiCondensed";
-        font-style-italic = "ExtraLight Italic";
-        font-style-bold-italic = "ExtraLight";
+        font-size = 14;
+        font-family = "Berkeley Mono Variable";
+        font-family-bold-italic = "Monaspace Xenon";
+        font-style-bold-italic = "ExtraLight Italic";
         font-synthetic-style = false;
+        font-variation-italic = [ "wght=100" ];
 
-        adjust-cell-height = 2;
+        adjust-cell-height = 1;
+        adjust-cursor-thickness = 5;
         adjust-font-baseline = 1;
-        adjust-cursor-thickness = 4;
-        adjust-underline-position = 3;
+        adjust-underline-position = 2;
         adjust-underline-thickness = -1;
 
         mouse-hide-while-typing = true;
-        unfocused-split-opacity = 0.9;
-        unfocused-split-fill = "#056157";
+        cursor-style = "block";
+        unfocused-split-opacity = 1.0;
 
         shell-integration = "fish";
 
-        gtk-tabs-location = "hidden";
+        window-decoration = false;
+        gtk-tabs-location = "bottom";
         gtk-titlebar = false;
-        gtk-titlebar-hide-when-maximized = true;
-        window-height = 60;
-        window-width = 160;
+        window-padding-x = 12;
+        window-padding-y = 0;
         window-padding-balance = true;
         window-padding-color = "extend";
         window-theme = "system";
-        theme = "light:PatagiaLight,dark:PatagiaDark";
 
         keybind = [
           "alt+shift+c=copy_to_clipboard"
           "alt+shift+v=paste_from_clipboard"
-          "ctrl+i=text:\\x09"
-          "ctrl+m=text:\\x0D"
           "ctrl+tab=goto_split:previous"
-          "alt+`=goto_split:previous"
-          "ctrl+[=text:\\x1B"
           "super+enter=toggle_fullscreen"
+          "ctrl+enter=unbind"
+          "alt+one=unbind"
+          "alt+two=unbind"
+          "alt+three=unbind"
+          "alt+four=unbind"
+          "alt+five=unbind"
+          "alt+six=unbind"
+          "alt+seven=unbind"
+          "alt+eight=unbind"
+          "alt+nine=unbind"
         ];
       };
-      themes = {
-        PatagiaDark = {
-          background = "#14151a";
-          foreground = "#b7bec7";
-          cursor-color = "#e7e7b7";
-          selection-background = "#84979f";
-          selection-foreground = "#000000";
-        };
-        PatagiaLight = {
-          background = "#fefeff";
-          foreground = "#222222";
-          cursor-color = "#aa0000";
-          selection-background = "#ffe6a4";
-          selection-foreground = "#483600";
-        };
-      };
     };
 
+    xdg.configFile."ghostty/theme_dark".text = ''
+      background = #0d1117
+      foreground = #b2b2b2
+      cursor-color = #00d992
+      selection-background = #d7d7d7
+      selection-foreground = #000000
+      palette = 0=#000000
+      palette = 1=#ff0035
+      palette = 2=#85ff00
+      palette = 3=#ffc900
+      palette = 4=#00a7ff
+      palette = 5=#cb01ff
+      palette = 6=#00e0ff
+      palette = 7=#f0f0f0
+      palette = 8=#444444
+      palette = 9=#ff8c88
+      palette = 10=#baff94
+      palette = 11=#ffe090
+      palette = 12=#88ccff
+      palette = 13=#e38dff
+      palette = 14=#97eeff
+      palette = 15=#ffffff
+    '';
+
+    xdg.configFile."ghostty/theme_light".text = ''
+      background = #fefeff
+      foreground = #222222
+      cursor-color = #aa0000
+      selection-background = #ffe6a4
+      selection-foreground = #483600
+      palette = 0=#000000
+      palette = 1=#9e001d
+      palette = 2=#306300
+      palette = 3=#deae00
+      palette = 4=#00669e
+      palette = 5=#7d009e
+      palette = 6=#008a9e
+      palette = 7=#f7f7f7
+      palette = 8=#b0b0b0
+      palette = 9=#ff0035
+      palette = 10=#509e00
+      palette = 11=#ffc900
+      palette = 12=#00a7ff
+      palette = 13=#cb01ff
+      palette = 14=#00e0ff
+      palette = 15=#ffffff
+    '';
+
     xdg.desktopEntries = {
-      ghostty-secondary = {
+      ghostty-local = {
         categories = [
           "System"
           "TerminalEmulator"
         ];
-        exec = ''
-          ghostty --class=com.mitchellh.ghostty-secondary --background-opacity=0.8 --font-style="UltraCondensed" --font-style-bold="Bold UltraCondensed" --font-style-italic="UltraCondensed Oblique" -e bash
-        '';
-        genericName = "Secondary Ghostty";
+        exec = ''launch-ghostty --class=com.mitchellh.ghostty-local -e "tmux new-session -A -s0 -nt1"'';
+        genericName = "Ghostty (local)";
         icon = "com.mitchellh.ghostty";
-        name = "Secondary Ghostty";
+        name = "Ghostty (local)";
         settings = {
-          StartupWMClass = "com.mitchellh.ghostty-secondary";
-          TryExec = "ghostty";
+          StartupWMClass = "com.mitchellh.ghostty-local";
+          TryExec = "launch-ghostty";
         };
         terminal = false;
         type = "Application";
       };
 
-      ghostty-devel = {
+      ghostty-nemo = {
         categories = [
           "System"
           "TerminalEmulator"
         ];
-        exec = ''
-          ghostty --class=com.mitchellh.ghostty-devel --command="ssh -t devel" --initial-command="ssh -t devel"
-        '';
-        genericName = "Ghostty (devel)";
+        exec = ''launch-ghostty --class=com.mitchellh.ghostty-nemo -e "ssh -t nemo tmux new-session -A -s0 -nt1"'';
+        genericName = "Ghostty (nemo)";
         icon = "com.mitchellh.ghostty";
-        name = "Ghostty (devel)";
+        name = "Ghostty (nemo)";
         settings = {
-          StartupWMClass = "com.mitchellh.ghostty-devel";
-          TryExec = "ghostty";
-        };
-        terminal = false;
-        type = "Application";
-      };
-
-      ghostty-devel-secondary = {
-        categories = [
-          "System"
-          "TerminalEmulator"
-        ];
-        exec = ''
-          ghostty --class=com.mitchellh.ghostty-devel-secondary --background-opacity=0.8 --font-style="ExtraCondensed" --font-style-bold="Bold ExtraCondensed" --font-style-italic="ExtraCondensed Oblique" --command="ssh -t devel" --initial-command="ssh -t devel"
-        '';
-        genericName = "Secondary Ghostty (devel)";
-        icon = "com.mitchellh.ghostty";
-        name = "Secondary Ghostty (devel)";
-        settings = {
-          StartupWMClass = "com.mitchellh.ghostty-devel-secondary";
-          TryExec = "ghostty";
+          StartupWMClass = "com.mitchellh.ghostty-nemo";
+          TryExec = "launch-ghostty";
         };
         terminal = false;
         type = "Application";
diff --git a/home/common/gnome.nix b/home/common/gnome.nix
index c2e64a7..de67eb7 100644
--- a/home/common/gnome.nix
+++ b/home/common/gnome.nix
@@ -8,17 +8,32 @@ with lib.hm.gvariant;
 {
   config = lib.mkIf config.patagia.desktop.enable {
     home.packages = with pkgs; [
-      gnome-contacts
-      gnome-shell-extensions
       gnome-tweaks
       gnome-pomodoro
       gnomeExtensions.desktop-clock
       gnomeExtensions.emoji-copy
       gnomeExtensions.just-perfection
-      gnomeExtensions.night-light-slider
+      gnomeExtensions.vitals
     ];
 
     dconf.settings = {
+      "org/gnome/desktop/background" = {
+        color-shading-type = "solid";
+        picture-options = "zoom";
+        picture-uri = "file:///run/current-system/sw/share/backgrounds/gnome/vnc-l.png";
+        picture-uri-dark = "file:///run/current-system/sw/share/backgrounds/gnome/vnc-d.png";
+        primary-color = "#77767B";
+        secondary-color = "#000000";
+      };
+
+      "org/gnome/desktop/screensaver" = {
+        color-shading-type = "solid";
+        picture-options = "zoom";
+        picture-uri = "file:///run/current-system/sw/share/backgrounds/gnome/vnc-l.png";
+        primary-color = "#77767B";
+        secondary-color = "#000000";
+      };
+
       "org/gnome/desktop/wm/keybindings" = {
         close = [ "<Super>q" ];
         toggle-on-all-workspaces = [ "<Super>s" ];
@@ -27,7 +42,6 @@ with lib.hm.gvariant;
         minimize = [ "<Super>comma" ];
         move-to-center = [ "<Super>c" ];
         switch-applications = [ "<Super>Tab" ];
-        switch-group = [ "<Super>Above_Tab" ];
         switch-windows = [ "<Alt>Tab" ];
         move-to-workspace-1 = [ "<Shift>F1" ];
         move-to-workspace-2 = [ "<Shift>F2" ];
@@ -69,9 +83,11 @@ with lib.hm.gvariant;
         enable-animations = false;
         enable-hot-corners = false;
         show-battery-percentage = true;
+        font-antialiasing = "grayscale";
+        font-hinting = "slight";
         font-name = "Inter Variable 11";
         document-font-name = "Inter Variable 11";
-        monospace-font-name = "Berkeley Mono 11";
+        monospace-font-name = "BerkeleyMono Nerd Font 11";
         toolkit-accessibility = false;
       };
 
@@ -137,7 +153,7 @@ with lib.hm.gvariant;
       };
 
       "org/gnome/mutter" = {
-        center-new-windows = false;
+        center-new-windows = true;
         edge-tiling = true;
       };
 
@@ -152,6 +168,7 @@ with lib.hm.gvariant;
         enabled-extensions = [
           "emoji-copy@felipeftn"
           "just-perfection-desktop@just-perfection"
+          "Vitals@CoreCoding.com"
         ];
       };
 
@@ -170,6 +187,10 @@ with lib.hm.gvariant;
         top-panel-position = 0;
       };
 
+      "org/gnome/shell/extensions/vitals" = {
+        update-time = 15;
+      };
+
       "org/gnome/tweaks" = {
         show-extensions-notice = false;
       };
diff --git a/home/common/nvim/blink-cmp.lua b/home/common/nvim/blink-cmp.lua
deleted file mode 100644
index ea0124d..0000000
--- a/home/common/nvim/blink-cmp.lua
+++ /dev/null
@@ -1,81 +0,0 @@
-require 'blink-cmp'.setup({
-  keymap = {
-    preset = 'enter',
-    ['<Tab>'] = { 'select_next', 'fallback' },
-    ['<S-Tab>'] = { 'select_prev', 'fallback' },
-    ['<PageDown>'] = { 'scroll_documentation_down', 'fallback' },
-    ['<PageUp>'] = { 'scroll_documentation_up', 'fallback' },
-  },
-  completion = {
-    accept = {
-      auto_brackets = { enabled = true, },
-    },
-
-    documentation = {
-      auto_show = true,
-      auto_show_delay_ms = 800,
-      window = { border = 'rounded', },
-    },
-
-    ghost_text = { enabled = false },
-
-    list = {
-      selection = {
-        preselect = false,
-        auto_insert = false
-      },
-    },
-
-    menu = {
-      auto_show = true,
-      border = 'rounded',
-      direction_priority = { 'n', 's' },
-      draw = {
-        components = {
-          kind_icon = {
-            ellipsis = false,
-            text = function(ctx)
-              local kind_icon, _, _ = require('mini.icons').get('lsp', ctx.kind)
-              return kind_icon
-            end,
-            -- Optionally, you may also use the highlights from mini.icons
-            highlight = function(ctx)
-              local _, hl, _ = require('mini.icons').get('lsp', ctx.kind)
-              return hl
-            end,
-          }
-        }
-      }
-    }
-  },
-
-  fuzzy = {
-    prebuilt_binaries = {
-      download = false
-    },
-  },
-
-  signature = {
-    enabled = true,
-    window = { border = 'rounded', },
-  },
-
-  cmdline = {
-    sources = {},
-  },
-
-  sources = {
-    default = {
-      'lsp',
-      'emoji',
-    },
-    providers = {
-      emoji = {
-        module = "blink-emoji",
-        name = "Emoji",
-        score_offset = 1,
-        opts = { insert = true },
-      }
-    },
-  },
-})
diff --git a/home/common/nvim/default.nix b/home/common/nvim/default.nix
index 94a6c4a..04b5299 100644
--- a/home/common/nvim/default.nix
+++ b/home/common/nvim/default.nix
@@ -4,23 +4,11 @@
   pkgs,
   ...
 }:
-let
-  nvim-remote = pkgs.writeShellApplication {
-    name = "nvim-remote";
-    text = ''
-      _sess=$(echo -n "$USER@''${SSH_CONNECTION:-$HOSTNAME}" | tr -c '[:alnum:]@.' '_')
-      _nvim_sock="''${XDG_RUNTIME_DIR:-/tmp}/nvim.$_sess.sock"
-      exec nvim --listen "$_nvim_sock" --server "$_nvim_sock" "$@"
-    '';
-  };
-in
 {
   imports = [
     ./treesitter.nix
   ];
 
-  home.packages = [ nvim-remote ];
-
   programs.man.generateCaches = false;
 
   programs.neovim = {
@@ -36,39 +24,34 @@ in
     extraLuaConfig = lib.fileContents ./init.lua;
 
     extraPackages = with pkgs; [
+      black
       codeium
+      cue
+      go
+      gopls
+      gotools
       lua-language-server
+      nil
       nixd
+      nodePackages.prettier
+      nodePackages.typescript
+      nodePackages.typescript-language-server
+      nodePackages.bash-language-server
+      rust-analyzer
+      rustfmt
       shellcheck
       shfmt
       stylua
+      vscode-langservers-extracted
     ];
 
     plugins = with pkgs.vimPlugins; [
-      blink-compat
-      blink-emoji-nvim
       friendly-snippets
       go-nvim
+      rustaceanvim
       targets-vim
       ts-comments-nvim
 
-      {
-        plugin = pkgs.vimUtils.buildVimPlugin {
-          name = "direnv-nvim";
-          src = pkgs.fetchFromGitHub {
-            owner = "actionshrimp";
-            repo = "direnv.nvim";
-            rev = "main";
-            hash = "sha256-7NcVskgAurbIuEVIXxHvXZfYQBOEXLURGzllfVEQKNE=";
-          };
-        };
-        type = "lua";
-        config = ''
-          require('direnv-nvim').setup {
-            type = "dir"
-          }
-        '';
-      }
       {
         plugin = nvim-lspconfig;
         type = "lua";
@@ -76,25 +59,47 @@ in
       }
 
       {
-        plugin = blink-cmp;
+        plugin = pkgs.nixpkgs-unstable.vimPlugins.blink-cmp;
         type = "lua";
-        config = lib.fileContents ./blink-cmp.lua;
+        config = ''
+          require'blink-cmp'.setup({
+            keymap = {
+              preset = 'enter',
+              ["<PageDown>"] = { "scroll_documentation_down" },
+              ["<PageUp>"] = { "scroll_documentation_up" },
+            },
+            trigger = {
+              completion = {
+                show_in_snippet = true,
+              },
+              signature_help = {
+                enabled = true,
+              },
+            },
+            windows = {
+              autocomplete = {
+                border = 'none',
+                selection = 'preselect',
+              },
+              documentation = {
+                border = 'rounded',
+                auto_show = false,
+                auto_show_delay_ms = 800,
+              },
+              signature_help = {
+                border = 'rounded',
+              },
+            },
+          })
+        '';
       }
 
       {
-        plugin = pkgs.vimUtils.buildVimPlugin {
-          name = "inlay-hints";
-          src = pkgs.fetchFromGitHub {
-            owner = "MysticalDevil";
-            repo = "inlay-hints.nvim";
-            rev = "3259b54f3b954b4d8260f3ee49ceabe978ea5636";
-            hash = "sha256-99KCGoPowa4PA1jkCm4ZbbgrFl84NWnKQMgkfy8KS5E=";
-          };
-        };
+        plugin = codeium-nvim;
         type = "lua";
         config = ''
-          require('inlay-hints').setup {
-            autocmd = { enable = false },
+          require'codeium'.setup {
+            enable_chat = false,
           }
         '';
       }
@@ -105,25 +110,43 @@ in
           src = pkgs.fetchFromGitHub {
             owner = "monkoose";
             repo = "neocodeium";
-            rev = "a2b5257c736886ec3ccbd961766f8ab9c82b2a72"; # 2025-02-04
-            hash = "sha256-mR2fzsdCVbh7nLcsSgQnhRivoKW6oFqJwuIYfz8OV0k=";
+            rev = "4da81528468b33585c411f31eb390dce573ccb14"; # v1.8.0
+            hash = "sha256-1n9nNqBNwNDSzbAkm8eB4HZLNy5HmMg25jPwQAnW5OU=";
           };
-          doCheck = false;
         };
         type = "lua";
         config = ''
           local neocodeium =require('neocodeium')
-          neocodeium.setup({
-            show_label = false,
-            debounce = true,
-            silent = false,
-          })
+          neocodeium.setup()
           vim.keymap.set("i", "<C-j>", neocodeium.accept, { remap = true })
           vim.keymap.set("i", "<A-f>", neocodeium.accept, { remap = true })
           vim.keymap.set("i", "<C-h>", neocodeium.cycle_or_complete, { remap = true })
         '';
       }
 
+      {
+        plugin = pkgs.vimUtils.buildVimPlugin {
+          name = "diagflow";
+          src = pkgs.fetchFromGitHub {
+            owner = "dgagn";
+            repo = "diagflow.nvim";
+            rev = "fc09d55d2e60edc8ed8f9939ba97b7b7e6488c99";
+            hash = "sha256-2WNuaIEXcAgUl2Kb/cCHEOrtehw9alaoM96qb4MLArw=";
+          };
+        };
+        type = "lua";
+        config = ''
+          require('diagflow').setup {
+            scope = "line",
+            gap_size = 0,
+            max_width = 50,
+            max_height = 20,
+            show_borders = true,
+            toggle_event = { "InsertEnter", "InsertLeave" },
+          }
+        '';
+      }
+
       {
         plugin = pkgs.vimUtils.buildVimPlugin {
           name = "dieter-nvim";
@@ -131,7 +154,7 @@ in
         };
         type = "lua";
         config = ''
-          vim.cmd.colorscheme "dieter-nocolor"
+          vim.cmd.colorscheme "dieter"
         '';
       }
 
@@ -140,13 +163,6 @@ in
         type = "lua";
         config = lib.fileContents ./mini.lua;
       }
-
-      {
-        plugin = rustaceanvim;
-        type = "lua";
-        config = lib.fileContents ./rust.lua;
-      }
-
     ];
   };
 }
diff --git a/home/common/nvim/dieter/colors/dieter-nocolor.lua b/home/common/nvim/dieter/colors/dieter-nocolor.lua
deleted file mode 100644
index 6f016e4..0000000
--- a/home/common/nvim/dieter/colors/dieter-nocolor.lua
+++ /dev/null
@@ -1,2 +0,0 @@
-package.loaded["dieter"] = nil
-require("dieter").setup_nocolor()
diff --git a/home/common/nvim/dieter/colors/dieter.lua b/home/common/nvim/dieter/colors/dieter.lua
index 5dd7a50..38e858c 100644
--- a/home/common/nvim/dieter/colors/dieter.lua
+++ b/home/common/nvim/dieter/colors/dieter.lua
@@ -1,2 +1,2 @@
 package.loaded["dieter"] = nil
-require("dieter").setup()
+require("dieter")
diff --git a/home/common/nvim/dieter/lua/dieter/init.lua b/home/common/nvim/dieter/lua/dieter/init.lua
index 6c5eebb..1e0d459 100644
--- a/home/common/nvim/dieter/lua/dieter/init.lua
+++ b/home/common/nvim/dieter/lua/dieter/init.lua
@@ -2,28 +2,18 @@ local hsl = require("dieter.hsl").hslToHex
 
 local colors = {
   light = {
-    background = "NONE",
-    foreground = "NONE",
+    background = hsl(240, 100, 100),
+    foreground = hsl(0, 0, 13),
 
     accent1 = hsl(12, 100, 50),
 
     dimmed = hsl(0, 0, 80),
     dimmed_subtle = hsl(0, 0, 20),
 
-    highlight_subtle = hsl(0, 0, 94),
-    highlight = hsl(0, 0, 90),
-    highlight_intense = hsl(42, 100, 30),
-
-    dialog_fg = hsl(230, 13, 10),
-    dialog_bg = hsl(50, 15, 95),
-    dialog_border = hsl(50, 25, 75),
-
     string = hsl(96, 50, 33),
-    comment = hsl(360, 66, 40),
+    comment = hsl(230, 66, 40),
     comment_error = hsl(2, 85, 40),
 
-    suggestion = hsl(220, 95, 55),
-
     diagnostic_error = hsl(347, 80, 45),
     diagnostic_warning = hsl(30, 100, 50),
     diagnostic_info = hsl(145, 80, 30),
@@ -39,51 +29,35 @@ local colors = {
     change = hsl(41, 80, 80),
     change_quarter = hsl(224, 100, 85),
     delete = hsl(350, 100, 40),
+    delete_quarter = hsl(350, 100, 85),
 
-    selection = hsl(270, 45, 92),
+    dialog_bg = hsl(224, 5, 92),
+    selection = hsl(270, 75, 92),
+    highlight_subtle = hsl(0, 0, 94),
+    highlight_intense = hsl(42, 100, 30),
 
-    search_bg = hsl(43, 100, 8),
-    search_fg = hsl(43, 100, 85),
-
-    cmp_bg = hsl(218, 30, 97),
-    cmp_fg = hsl(218, 30, 13),
-    cmp_selected_fg = hsl(218, 50, 8),
-    cmp_selected_bg = hsl(218, 30, 85),
-
-    doc_bg = hsl(200, 30, 90),
-    doc_fg = hsl(220, 80, 10),
   },
 
   dark = {
-    background = "NONE",
-    foreground = "NONE",
+    background = hsl(216, 28, 7),
+    foreground = hsl(0, 0, 80),
 
-    accent1 = hsl(202, 57, 57), -- Blue
-    accent2 = hsl(40, 57, 57),  -- Yellow
+    accent1 = hsl(12, 100, 50),
 
-    dimmed = hsl(212, 19, 25),
-    dimmed_subtle = hsl(212, 19, 50),
+    dimmed = hsl(0, 0, 25),
+    dimmed_subtle = hsl(0, 0, 50),
 
-    highlight_subtle = hsl(212, 27, 11),
-    highlight = hsl(212, 27, 18),
+    highlight_subtle = hsl(0, 0, 6),
     highlight_intense = hsl(58, 100, 60),
 
-    dialog_fg = hsl(191, 15, 75),
-    dialog_bg = "NONE",
-
-    string = hsl(90, 30, 60),
-    comment = hsl(216, 30, 55),
+    string = hsl(96, 50, 70),
+    comment = hsl(220, 50, 60),
     comment_error = hsl(2, 85, 50),
-    func = hsl(40, 57, 87),
-    member = hsl(213, 45, 75),
-    punc = hsl(213, 45, 50),
-
-    suggestion = hsl(158, 66, 40),
 
     diagnostic_error = hsl(353, 100, 45),
     diagnostic_warning = hsl(30, 100, 50),
     diagnostic_info = hsl(176, 80, 60),
-    diagnostic_hint = hsl(210, 74, 60),
+    diagnostic_hint = hsl(176, 80, 60),
 
     popup_error_bg = hsl(0, 95, 7),
     popup_warning_bg = hsl(27, 95, 7),
@@ -97,197 +71,145 @@ local colors = {
     delete = hsl(350, 100, 40),
     delete_quarter = hsl(350, 100, 15),
 
-    selection = hsl(218, 90, 20),
-
-    search_bg = hsl(43, 100, 8),
-    search_fg = hsl(43, 100, 85),
+    -- dialog_bg = background,
+    -- dialog_fg = hsl(216, 70, 80),
+    -- dialog_bg = hsl(216, 25, 20),
+    -- selection = hsl(216, 25, 33),
+    selection = hsl(213, 60, 40),
 
     cmp_bg = hsl(218, 30, 13),
-    cmp_fg = hsl(218, 30, 80),
+    cmp_fg = hsl(218, 30, 60),
     cmp_selected_bg = hsl(218, 30, 25),
     cmp_selected_fg = hsl(218, 50, 80),
 
     doc_bg = hsl(220, 80, 10),
     doc_fg = hsl(200, 30, 60),
+
+    suggestion = hsl(180, 55, 40),
   },
 
 }
 
-local setupGroups = function(c)
+local c = colors[vim.o.background]
+c.dialog_fg = c.foreground
+c.dialog_bg = c.background
 
-  return {
-    Normal = { fg = c.foreground, bg = c.background },
+local theme = {
+  Normal = { fg = c.foreground, bg = c.background },
 
-    Constant = { link = "NormalNC" },
-    Delimiter = { link = "NormalNC" },
-    Function = { fg = c.func },
-    Identifier = { link = "NormalNC" },
-    Keyword = { fg = c.foreground, bold = true },
-    Operator = { link = "NormalNC" },
-    Special = { link = "NormalNC" },
-    Type = { link = "NormalNC" },
+  Constant = { link = "NormalNC" },
+  Delimiter = { link = "NormalNC" },
+  Identifier = { link = "NormalNC" },
+  Keyword = { fg = c.foreground, bold = true },
+  Operator = { link = "NormalNC" },
+  Special = { link = "NormalNC" },
+  Type = { link = "NormalNC" },
 
-    MsgArea = { fg = c.dimmed_subtle },
-    StatusLine = { fg = c.dimmed, bg = c.dimmed_subtle },
+  String = { fg = c.string },
 
-    String = { fg = c.string },
+  Comment = { fg = c.comment, italic = true, bold = true },
+  CommentError = { fg = c.comment_error, italic = true, bold = true },
+  ["@comment.note"] = { link = "Comment" },
+  ["@comment.todo"] = { link = "CommentError" },
+  ["@comment.error"] = { link = "CommentError" },
+  ["@comment.warning"] = { link = "CommentError" },
 
-    Visual = { bg = c.selection },
+  DiffAdd = { fg = c.add, bg = c.add_quarter },
+  GitSignsAdd = { fg = c.add, bg = c.background },
+  GitSignsAddNr = { link = "DiffAdd" },
+  DiffChange = { fg = c.change, bg = c.change_quarter },
+  GitSignsChange = { fg = c.change, bg = c.background },
+  GitSignsChangeNr = { link = "DiffChange" },
+  DiffDelete = { fg = c.delete, bg = c.delete_quarter },
+  GitSignsDelete = { fg = c.delete, bg = c.background },
+  GitSignsDeleteNr = { link = "DiffDelete" },
 
-    Search = { bg = c.search_bg, fg = c.search_fg },
-    CurSearch = { link = "Search" },
+  -- Treesitter
+  ["@function"] = { link = "NormalNC" },
+  ["@special"] = { link = "NormalNC" },
+  ["@variable"] = { link = "NormalNC" },
+  ["@lsp.type.variable"] = { fg = c.dimmed_subtle },
 
-    Comment = { fg = c.comment, italic = true },
-    CommentError = { fg = c.comment_error, italic = true },
-    ["@comment.note"] = { link = "Comment" },
-    ["@comment.todo"] = { link = "CommentError" },
-    ["@comment.error"] = { link = "CommentError" },
-    ["@comment.warning"] = { link = "CommentError" },
+  -- UI Elements
+  CursorLine = { bg = c.highlight_subtle },
 
-    DiffAdd = { fg = c.add, bg = c.add_quarter },
-    GitSignsAdd = { fg = c.add, bg = c.background },
-    GitSignsAddNr = { link = "DiffAdd" },
-    DiffChange = { fg = c.change, bg = c.change_quarter },
-    GitSignsChange = { fg = c.change, bg = c.background },
-    GitSignsChangeNr = { link = "DiffChange" },
-    DiffDelete = { fg = c.delete, bg = c.delete_quarter },
-    GitSignsDelete = { fg = c.delete, bg = c.background },
-    GitSignsDeleteNr = { link = "DiffDelete" },
+  DiagnosticError = { fg = c.diagnostic_error, italic = true },
+  DiagnosticFloatingError = { fg = c.diagnostic_error, bg = c.popup_error_bg },
+  DiagnosticFloatingWarn = { fg = c.diagnostic_warning, bg = c.popup_warning_bg },
+  DiagnosticFloatingInfo = { fg = c.diagnostic_info, bg = c.popup_info_bg },
+  DiagnosticFloatingHint = { fg = c.diagnostic_hint, bg = c.popup_hint_bg },
+  DiagnosticUnderlineError = { fg = c.diagnostic_error, undercurl = true },
+  DiagnosticUnderlineWarn = { fg = c.diagnostic_warn, undercurl = true },
+  DiagnosticUnderlineInfo = { fg = c.diagnostic_info, undercurl = true },
+  DiagnosticUnderlinehint = { fg = c.diagnostic_hint, undercurl = true },
 
-    -- Treesitter
-    ["@punctuation.special"] = { fg = c.punc },
-    ["@special"] = { link = "NormalNC" },
-    ["@variable"] = { link = "NormalNC" },
-    ["@variable.member"] = { fg = c.member },
-    ["@variable.parameter"] = { fg = c.accent2 },
+  DiagnosticSignError = { fg = c.diagnostic_error },
+  DiagnosticSignHint = { fg = c.diagnostic_hint },
+  DiagnosticSignInfo = { fg = c.diagnostic_info },
+  DiagnosticSignWarn = { fg = c.diagnostic_warning },
+  LineNr = { fg = c.dimmed, italic = true },
+  IndentLine = { fg = c.background },
+  IndentLineCurrent = { fg = c.dimmed },
+  TreesitterContext = { reverse = true },
+  TreesitterContextLineNumber = { bg = c.dimmed, reverse = true, italic = true },
+  InclineNormal = { bg = c.background },
+  InclineNormalNC = { bg = c.background },
 
-    -- UI Elements
-    CursorLine = { bg = c.highlight_subtle },
+  WinSeparator = { bg = c.dialog_bg, fg = c.dialog_fg },
+  NormalFloat = { bg = c.doc_bg, fg = c.doc_fg },
+  FloatBorder = { fg = c.doc_fg },
+  FloatTitle = { fg = c.doc_fg, bold = true },
 
-    DiagnosticError = { fg = c.diagnostic_error, italic = true },
-    DiagnosticHint = { fg = c.diagnostic_hint, italic = true },
-    DiagnosticInfo = { fg = c.diagnostic_info, italic = true },
-    DiagnosticWarn = { fg = c.diagnostic_warn, italic = true },
-    DiagnosticFloatingError = { fg = c.diagnostic_error, bg = c.dialog_bg },
-    DiagnosticFloatingHint = { fg = c.diagnostic_hint, bg = c.dialog_bg },
-    DiagnosticFloatingInfo = { fg = c.diagnostic_info, bg = c.dialog_bg },
-    DiagnosticFloatingWarn = { fg = c.diagnostic_warning, bg = c.dialog_bg },
-    DiagnosticUnderlineError = { fg = c.foreground, undercurl = true, sp = c.diagnostic_error },
-    DiagnosticUnderlineHint = { fg = c.foreground, undercurl = true, sp = c.diagnostic_hint },
-    DiagnosticUnderlineInfo = { fg = c.foreground, undercurl = true, sp = c.diagnostic_info },
-    DiagnosticUnderlineWarn = { fg = c.foreground, undercurl = true, sp = c.diagnostic_warn },
+  Title = { fg = c.foreground, bold = true },
 
-    DiagnosticSignError = { fg = c.diagnostic_error },
-    DiagnosticSignHint = { fg = c.diagnostic_hint },
-    DiagnosticSignInfo = { fg = c.diagnostic_info },
-    DiagnosticSignWarn = { fg = c.diagnostic_warning },
-    LineNr = { fg = c.dimmed },
-    CursorLineNr = { fg = c.dimmed_subtle, bg = c.highlight_subtle },
+  MiniPickNormal = { link = "Normal" },
+  MiniPickBorder = { link = "MiniPickNormal" },
+  MiniPickBorderText = { link = "MiniPickBorder" },
+  MiniPickMatchCurrent = { bg = c.background, fg = c.foreground, reverse = true },
 
-    IndentLine = { fg = c.highlight },
-    IndentLineCurrent = { fg = c.highlight },
-    MiniIndentscopeSymbol = { link = "IndentLine" },
-    MiniIndentscopeSymbolOff = { link = "IndentLine" },
+  MiniClueBorder = { link = "MiniPickNormal" },
+  MiniClueTitle = { bg = c.background, fg = c.foreground, bold = true },
+  MiniClueNextKey = { link = "MiniClueTitle" },
+  MiniClueDescGroup = { bg = c.background, fg = c.foreground, italic = true },
+  MiniClueDescSingle = { bg = c.background, fg = c.foreground },
+  MiniClueSeparator = { link = "MiniClueBorder" },
 
-    TreesitterContext = { reverse = true },
-    TreesitterContextLineNumber = { bg = c.dimmed, reverse = true, italic = true },
-    InclineNormal = { bg = c.background },
-    InclineNormalNC = { bg = c.background },
+  MiniStarterCurrent = { link = "MiniPickMatchCurrent" },
 
-    EndOfBuffer = { fg = c.dimmed },
-    WinSeparator = { bg = c.dialog_bg, fg = c.dialog_fg },
-    NormalFloat = { bg = c.dialog_bg, fg = c.foreground },
-    FloatBorder = { bg = c.dialog_bg, fg = c.dialog_border },
-    FloatTitle = { bg = c.dialog_bg, fg = c.dialog_border, bold = true },
+  BlinkCmpMenu = { bg = c.cmp_bg, fg = c.cmp_fg },
+  BlinkCmpMenuSelection = { bg = c.cmp_selected_bg, fg = c.cmp_selected_fg, reverse = false },
+  BlinkCmpMenuBorder = { bg = c.cmp_bg, fg = c.cmp_fg },
+  BlinkCmpLabel = { link = 'BlinkCmpMenu' },
+  BlinkCmpLabelMatch = { link = 'BlinkCmpMenu', underline = true },
 
-    Title = { fg = c.foreground, bold = true },
+  BlinkCmpDoc = { bg = c.doc_bg, fg = c.foreground },
+  BlinkCmpDocBorder = { bg = c.doc_bg, fg = c.doc_fg },
+  BlinkCmpDocDetail = { link = 'BlinkCmpDoc' },
+  BlinkCmpSignatureHelp = { link = 'BlinkCmpDoc' },
+  BlinkCmpSignatureHelpBorder = { link = 'BlinkCmpDocBorder' },
 
-    MiniPickNormal = { bg = c.dialog_bg, fg = c.dialog_fg },
-    MiniPickBorder = { bg = c.dialog_bg, fg = c.dialog_border },
-    MiniPickBorderText = { link = "MiniPickBorder" },
-    MiniPickMatchCurrent = { bg = c.dialog_bg, fg = c.dialog_fg, reverse = true },
+  NeoCodeiumSuggestion = { fg = c.suggestion , bold = true, italic = true },
 
-    MiniClueBorder = { link = "MiniPickBorder" },
-    MiniClueTitle = { bg = c.dialog_bg, fg = c.dialog_border, bold = true },
-    MiniClueNextKey = { link = "MiniClueTitle" },
-    MiniClueDescGroup = { bg = c.dialog_bg, fg = c.foreground, italic = true },
-    MiniClueDescSingle = { bg = c.dialog_bg, fg = c.foreground },
-    MiniClueSeparator = { link = "MiniClueBorder" },
+  NoiceMini = { fg = c.foreground, italic = true },
 
-    MiniCursorWord = { underdotted = true, bold = true, sp = c.diagnostic_hint },
+  TelescopeNormal = { fg = c.foreground, bg = c.background },
+  TelescopeBorder = { bold = true },
+  TelescopeSelection = { bg = c.selection },
+  TelescopeResultsNormal = { fg = c.foreground, bold = true },
+  TelescopeResultsComment = { fg = c.dimmed_subtle, italic = true, bold = false },
 
-    MiniStarterCurrent = { link = "MiniPickMatchCurrent" },
+  Visual = { bg = c.selection },
+  LspReferenceText = { fg = c.highlight_intense, undercurl = true },
+}
 
-    BlinkCmpMenu = { bg = c.cmp_bg, fg = c.cmp_fg },
-    BlinkCmpMenuSelection = { bg = c.cmp_selected_bg, fg = c.cmp_selected_fg, reverse = false },
-    BlinkCmpMenuBorder = { bg = c.cmp_bg, fg = c.cmp_fg },
-    BlinkCmpLabel = { link = 'BlinkCmpMenu' },
-    BlinkCmpLabelMatch = { link = 'BlinkCmpMenu', underline = true },
+vim.cmd("hi clear")
 
-    BlinkCmpDoc = { bg = c.doc_bg, fg = c.foreground },
-    BlinkCmpDocBorder = { bg = c.doc_bg, fg = c.doc_fg },
-    BlinkCmpDocDetail = { link = 'BlinkCmpDoc' },
-    BlinkCmpSignatureHelp = { link = 'BlinkCmpDoc' },
-    BlinkCmpSignatureHelpBorder = { link = 'BlinkCmpDocBorder' },
-
-    BlinkCmpGhostText = { fg = c.suggestion, italic = true, bold = true },
-    NeoCodeiumSuggestion = { link = 'BlinkCmpGhostText' },
-
-    LspReferenceText = { fg = c.highlight_intense, undercurl = true },
-    LspInlayHint = { fg = c.accent1, italic = true, bold = true },
-  }
+if vim.fn.exists("syntax_on") == 1 then
+  vim.cmd("syntax reset")
 end
 
-
-local setupGroupsNoColor = function(c)
-  local g = setupGroups(c)
-  local cl = { link = "NormalNC" }
-  g.Constant = cl
-  g.Delimiter = cl
-  g.Function = cl
-  g.Identifier = cl
-  g.Keyword = cl
-  g.Operator = cl
-  g["@punctuation.special"] = cl
-  g["@special"] = cl
-  g["@string"] = cl
-  g["@lsp.type.string"] = cl
-  g.Special = cl
-  g.String = cl
-  g.Type = cl
-  g.Variable = cl
-  g["@variable"] = cl
-  g["@variable.member"] = cl
-  g["@variable.parameter"] = cl
-  -- g.Comment = { fg = c.dimmed_subtle, italic = true, bold = true }
-  g.CommentError = { link = "Comment" }
-  return g
+for group, hl in pairs(theme) do
+  vim.api.nvim_set_hl(0, group, hl)
 end
 
-local setup_common = function(groups)
-  vim.cmd("hi clear")
-  if vim.fn.exists("syntax_on") == 1 then
-    vim.cmd("syntax reset")
-  end
-  for group, hl in pairs(groups) do
-    vim.api.nvim_set_hl(0, group, hl)
-  end
-end
-
-local T = {}
-
-T.setup = function()
-  local c = colors[vim.o.background]
-  local groups = setupGroups(c)
-  setup_common(groups)
-  vim.g.colors_name = "dieter"
-end
-
-T.setup_nocolor = function()
-  local c = colors[vim.o.background]
-  local groups = setupGroupsNoColor(c)
-  setup_common(groups)
-  vim.g.colors_name = "dieter-nocolor"
-end
-
-return T
+vim.g.colors_name = "dieter"
diff --git a/home/common/nvim/init.lua b/home/common/nvim/init.lua
index cd34947..90f5db6 100644
--- a/home/common/nvim/init.lua
+++ b/home/common/nvim/init.lua
@@ -1,15 +1,12 @@
-vim.env.RIPGREP_CONFIG_PATH = vim.env.HOME .. "/.config/ripgrep/ripgreprc"
-
 vim.g.mapleader = ' '
 vim.g.maplocalleader = ","
 
 -- UI
 
-vim.opt.cursorline = false
-vim.opt.guicursor =
-"n-v-c:block,i-ci-ve:ver25,r-cr:hor20,o:hor50,a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor,sm:block-blinkwait175-blinkoff150-blinkon175"
-vim.opt.number = false
-vim.opt.relativenumber = false
+vim.opt.cursorline = true
+vim.opt.laststatus = 0
+vim.opt.number = true
+vim.opt.relativenumber = true
 vim.opt.ruler = true
 vim.opt.syntax = "on"
 vim.opt.termguicolors = true
@@ -20,30 +17,12 @@ function GetIndicators()
   local counts = vim.diagnostic.count(bufnr)
   local errors = counts[vim.diagnostic.severity.ERROR] or 0
   local warnings = counts[vim.diagnostic.severity.WARN] or 0
-  local warn_string = warnings > 0 and "%#DiagnosticWarn# " .. warnings .. " " or ""
-  local error_string = errors > 0 and "%#DiagnosticError# " .. errors .. " " or ""
+  local warn_string = warnings > 0 and "%#DiagnosticWarn# " .. warnings .. " " or "  "
+  local error_string = errors > 0 and "%#DiagnosticError# " .. errors .. " " or "  "
   return warn_string .. error_string
 end
 
-function CondensedPath()
-  local path = vim.fn.expand("%:p")
-  local home = os.getenv("HOME")
-  if home then
-    path = vim.fn.substitute(path, '^' .. home, '~', '')
-  end
-
-  local segments = vim.fn.split(path, '/')
-  if #segments <= 3 then
-    return path
-  end
-
-  local early_path = table.concat(vim.list_slice(segments, 1, #segments - 2), '/')
-  local late_path = table.concat(vim.list_slice(segments, #segments - 1), '/')
-
-  return vim.fn.pathshorten(early_path) .. '/' .. late_path
-end
-
-vim.opt.statusline = "%{%v:lua.CondensedPath()%}%=%{%v:lua.GetIndicators()%}%7(%l:%c%)"
+vim.opt.rulerformat = "%40(%=%{%v:lua.GetIndicators()%}%#Label#│ %t %)"
 
 -- Search
 vim.opt.ignorecase = true
@@ -75,7 +54,7 @@ vim.opt.foldexpr = "nvim_treesitter#foldexpr()"
 
 vim.o.autochdir = true
 vim.o.cia = 'kind,abbr,menu'
-vim.o.fillchars = "stl: ,stlnc: ,eob:🮘,vert:│"
+vim.o.fillchars = "stl: ,stlnc: ,eob:░,vert:│"
 vim.o.icm = "split"
 vim.o.list = false
 vim.o.scrolloff = 7
@@ -84,51 +63,31 @@ vim.o.showcmd = false
 vim.o.showmode = false
 vim.o.smoothscroll = true
 vim.o.splitkeep = "screen"
-vim.o.timeout = false
-vim.o.updatetime = 250
+vim.o.timeoutlen = 10
+vim.o.timeout = true
+vim.o.updatetime = 50
+
 
 -- Use rg
 vim.o.grepprg = [[rg --glob "!.jj" --glob "!.git" --no-heading --vimgrep --follow $*]]
 vim.opt.grepformat = vim.opt.grepformat ^ { "%f:%l:%c:%m" }
 
--- Diagnostics
-vim.diagnostic.config {
-  float = {
-    border = "rounded",
-    header = "",
-    source = "if_many",
-  },
-  severity_sort = true,
-  signs = {
-    linehl = {
-      [vim.diagnostic.severity.ERROR] = "DiagnosticSignErrorLine",
-      [vim.diagnostic.severity.WARN] = "DiagnosticSignWarnLine",
-      [vim.diagnostic.severity.INFO] = "DiagnosticSignInfoLine",
-      [vim.diagnostic.severity.HINT] = "DiagnostigSignHintLine",
-    },
-    numhl = {
-      [vim.diagnostic.severity.ERROR] = "DiagnosticSignError",
-      [vim.diagnostic.severity.WARN] = "DiagnosticSignWarn",
-      [vim.diagnostic.severity.INFO] = "DiagnosticSignInfo",
-      [vim.diagnostic.severity.HINT] = "DiagnostigSignHint",
-    },
-    text = {
-      [vim.diagnostic.severity.ERROR] = "",
-      [vim.diagnostic.severity.WARN] = "",
-      [vim.diagnostic.severity.INFO] = "",
-      [vim.diagnostic.severity.HINT] = "",
-    },
-  },
-  virtual_lines = false,
-}
-vim.keymap.set('n', '<Space>ud', function()
-  if vim.diagnostic.config().virtual_lines == true then
-    -- vim.diagnostic.config({ virtual_lines = { current_line = true } })
-    vim.diagnostic.config({ virtual_lines = false })
-  else
-    vim.diagnostic.config({ virtual_lines = true })
-  end
-end, { desc = 'Toggle diagnostic virtual_lines' })
+vim.fn.sign_define(
+  "DiagnosticSignError",
+  { text = "", hl = "DiagnosticSignError", texthl = "DiagnosticSignError", culhl = "DiagnosticSignErrorLine" }
+)
+vim.fn.sign_define(
+  "DiagnosticSignWarn",
+  { text = "", hl = "DiagnosticSignWarn", texthl = "DiagnosticSignWarn", culhl = "DiagnosticSignWarnLine" }
+)
+vim.fn.sign_define(
+  "DiagnosticSignInfo",
+  { text = "", hl = "DiagnosticSignInfo", texthl = "DiagnosticSignInfo", culhl = "DiagnosticSignInfoLine" }
+)
+vim.fn.sign_define(
+  "DiagnosticSignHint",
+  { text = "", hl = "DiagnosticSignHint", texthl = "DiagnosticSignHint", culhl = "DiagnosticSignHintLine" }
+)
 
 
 -- Make <Tab> work for snippets
@@ -141,29 +100,6 @@ vim.keymap.set({ "i", "s" }, "<Tab>", function()
 end, { expr = true })
 
 
--- Autoformat
-
-vim.g.autoformat_enabled = true -- set to true by default
-
-vim.api.nvim_create_user_command('ToggleAutoFormat', function()
-  vim.g.autoformat_enabled = not vim.g.autoformat_enabled
-  print('Autoformatting ' .. (vim.g.autoformat_enabled and 'enabled' or 'disabled'))
-end, {})
-
-vim.api.nvim_create_augroup("AutoFormat", {})
-
-vim.api.nvim_create_autocmd("BufWritePre", {
-  group = "AutoFormat",
-  callback = function()
-    if vim.g.autoformat_enabled then
-      vim.lsp.buf.format({
-        async = false,
-        timeout_ms = 2000 -- Adjust timeout as needed
-      })
-    end
-  end,
-})
-
 -- Keymap
 local opts = function(label)
   return { noremap = true, silent = true, desc = label }
@@ -179,29 +115,20 @@ vim.keymap.set({ "n", "v" }, "<Leader>a", vim.lsp.buf.code_action, { remap = tru
 vim.keymap.set("n", "<Leader>af", function()
   vim.lsp.buf.format({ async = true })
 end, opts("Format Buffer"))
-vim.keymap.set('n', '<Leader><Leader>', "<cmd>Pick visit_paths cwd=''<cr>", opts("Visits"))
 vim.keymap.set('n', '<Leader>b', "<cmd>Pick buffers<cr>", opts("Open buffer picker"))
 vim.keymap.set('n', '<Leader>/', "<cmd>Pick grep_live_root<cr>", opts("Search workspace files"))
-vim.keymap.set('n', '<Leader>d', vim.diagnostic.open_float, opts("Show diagnostics for line"))
-vim.keymap.set('n', '<m-d>', vim.diagnostic.open_float, opts("Show diagnostics for line"))
-vim.keymap.set('n', '<Leader>D', function()
-  local width = vim.o.columns - 8
-  MiniExtra.pickers.diagnostic({ scope = "current" }, { window = { config = { width = width } } })
-end, opts("Open diagnostics picker"))
-
+vim.keymap.set('n', '<Leader>d', "<cmd>Pick diagnostic<cr>", opts("Open diagnostics picker"))
+vim.keymap.set("n", "<Leader>D", vim.diagnostic.setloclist, { desc = "Diagnostics to location list" })
 vim.keymap.set("n", "<Leader>r", vim.lsp.buf.rename, opts("Rename Symbol"))
 vim.keymap.set('n', '<Leader>F', "<cmd>Pick files<cr>", opts("Open file picker CWD"))
 vim.keymap.set('n', '<Leader>f', "<cmd>Pick files_root<cr>", opts("Open file picker"))
-vim.keymap.set('n', '<c-p>', "<Leader>f", { remap = true })
 vim.keymap.set('n', '<Leader>g', "<cmd>Pick oldfiles<cr>", opts("Open file picker history"))
 vim.keymap.set("n", '<Leader>k', vim.lsp.buf.hover, opts("Show docs for item under cursor"))
-vim.keymap.set('n', '<Leader>p', "<cmd>Pick projects<cr>", opts("Open projects picker"))
 vim.keymap.set('n', '<Leader>q', require('mini.bufremove').delete, opts("Delete buffer"))
 vim.keymap.set('n', '<Leader>s', "<cmd>Pick lsp scope='document_symbol'<cr>", opts("Open symbol picker"))
 vim.keymap.set('n', '<Leader>S', "<cmd>Pick lsp scope='workspace_symbol'<cr>", opts("Open workspace symbol picker"))
 vim.keymap.set("n", "<Leader>ws", "<C-w>s", opts("Horizontal split"))
 vim.keymap.set("n", "<Leader>wv", "<C-w>v", opts("Vertical split"))
-vim.keymap.set("n", "<m-f>", require('mini.files').open, opts("Open file manager"))
 vim.keymap.set('n', '<tab>', "<cmd>Pick buffers include_current=false<cr>", opts("Buffers"))
 vim.keymap.set("n", "zz", "zt", { remap = true })
 vim.keymap.set({ "n", "v" }, "<Leader>y", '"+y', opts("Yank to clipboard"))
@@ -219,23 +146,6 @@ vim.keymap.set("n", "K", function()
     max_width = 80,
     offset_x = 2,
   }
-end, {})
-vim.keymap.set("n", "<Leader>ub", function()
-  vim.o.background = (vim.o.background == "light" and "dark" or "light")
-end, opts("Toggle dark/light background"))
-vim.keymap.set("n", "<Leader>uc", function()
-  if vim.g.colors_name == "dieter-nocolor" then
-    vim.cmd [[colorscheme dieter]]
-  else
-    vim.cmd [[colorscheme dieter-nocolor]]
-  end
-end, opts("Toggle Dieter colors"))
-vim.keymap.set("n", "<Leader>uf", "<cmd>ToggleAutoFormat<cr>", opts("Toggle autoformat on save"))
-vim.keymap.set("n", "<Leader>uh", "<cmd>InlayHintsToggle<cr>", opts("Toggle inlay hints"))
-vim.keymap.set("n", "<Leader>ul", "<cmd>set invcursorline<cr>", opts("Toggle cursor line"))
-vim.keymap.set("n", "<Leader>un", "<cmd>set invnumber<cr>", opts("Toggle line numbers"))
-vim.keymap.set("n", "<Leader>uw", "<cmd>set invwrap<cr>", opts("Toggle line wrapping"))
+  end, {})
+
 
-vim.keymap.set("n", "<Leader>ui", function()
-  vim.g.miniindentscope_disable = not vim.g.miniindentscope_disable
-end, opts("Toggle indent scope"))
diff --git a/home/common/nvim/lsp.lua b/home/common/nvim/lsp.lua
index f36bd30..7a8d0c5 100644
--- a/home/common/nvim/lsp.lua
+++ b/home/common/nvim/lsp.lua
@@ -1,60 +1,44 @@
+local configs = require('lspconfig.configs')
 local lspconfig = require("lspconfig")
+local capabilities = vim.lsp.protocol.make_client_capabilities()
 local servers = {
-  cssls = {},
-  html = {},
-  jsonls = {},
-  sqls = {},
-  superhtml = {},
-  ts_ls = {},
-
-  gopls = {
-    settings = {
-      gopls = {
-        hints = {
-          rangeVariableTypes = true,
-          parameterNames = true,
-          constantValues = true,
-          assignVariableTypes = true,
-          compositeLiteralFields = true,
-          compositeLiteralTypes = true,
-          functionTypeParameters = true,
-        },
-      },
-    },
-  },
-
-  lua_ls = {
-    settings = {
-      Lua = {
-        runtime = {
-          version = "LuaJIT",
-          path = vim.split(package.path, ";"),
-        },
-        diagnostics = { globals = { "vim", "hs" } },
-        hint = { enable = true },
-        workspace = {
-          library = {
-            [vim.fn.expand("$VIMRUNTIME/lua")] = true,
-            [vim.fn.expand("$VIMRUNTIME/lua/vim/lsp")] = true,
-          },
-        },
-      },
-    },
-  },
-
-  nixd = {
-    cmd = { "nixd" },
-    settings = {
-      nixd = {
-        nixpkgs = { expr = "import <nixpkgs> { }" },
-        formatting = { command = { "nixfmt" } },
-        options = {},
-      },
-    },
-  },
+  'gopls',
+  'ts_ls',
 }
 
-for server, config in pairs(servers) do
-  config.capabilities = require('blink.cmp').get_lsp_capabilities(config.capabilities)
-  lspconfig[server].setup(config)
+for _, ls in ipairs(servers) do
+  lspconfig[ls].setup {
+    capabilities = capabilities,
+  }
 end
+
+lspconfig.nixd.setup({
+  capabilities = capabilities,
+  cmd = { "nixd" },
+  settings = {
+    nixd = {
+      nixpkgs = { expr = "import <nixpkgs> { }" },
+      formatting = { command = { "nixfmt" } },
+      options = {},
+    },
+  },
+})
+
+lspconfig.lua_ls.setup({
+  capabilities = capabilities,
+  settings = {
+    Lua = {
+      runtime = {
+        version = "LuaJIT",
+        path = vim.split(package.path, ";"),
+      },
+      diagnostics = { globals = { "vim", "hs" } },
+      workspace = {
+        library = {
+          [vim.fn.expand("$VIMRUNTIME/lua")] = true,
+          [vim.fn.expand("$VIMRUNTIME/lua/vim/lsp")] = true,
+        },
+      },
+    },
+  },
+})
diff --git a/home/common/nvim/mini.lua b/home/common/nvim/mini.lua
index 3c7d129..2c71357 100644
--- a/home/common/nvim/mini.lua
+++ b/home/common/nvim/mini.lua
@@ -5,13 +5,11 @@ require('mini.bufremove').setup()
 require('mini.comment').setup()
 require('mini.diff').setup()
 require('mini.extra').setup()
-require('mini.files').setup()
 require('mini.icons').setup()
 require('mini.jump').setup()
 require('mini.surround').setup()
 require('mini.splitjoin').setup()
 require('mini.trailspace').setup()
-require('mini.visits').setup()
 
 require('mini.cursorword').setup({
   delay = 800
@@ -37,7 +35,6 @@ indentscope.setup({
   },
   symbol = '│',
 })
-vim.g.miniindentscope_disable = true
 
 require('mini.jump2d').setup({
   mappings = { start_jumping = 'gw' }
@@ -52,14 +49,13 @@ local picker_win_config = function()
     height = height,
     width = width,
     row = 2,
-    col = 5,
+    col = math.floor((vim.o.columns - width) / 2),
   }
 end
 
 require('mini.pick').setup({
   mappings = {
     move_down      = '<tab>',
-    move_up        = '<S-tab>',
     toggle_info    = '<C-k>',
     toggle_preview = '<C-p>',
   },
@@ -68,58 +64,13 @@ require('mini.pick').setup({
     config = picker_win_config,
   },
 })
-
-local MiniPick = require('mini.pick')
-MiniPick.registry.projects = function(local_opts)
-  local root = vim.fn.expand("~/src")
-
-  local command = {
-    "fd",
-    "--max-depth=8",
-    "--one-file-system",
-    "--unrestricted",
-    "--full-path",
-    "/.jj/repo/store/type$|/.git/HEAD$",
-    root,
-  }
-
-  local postprocess = function(paths)
-    local result = {}
-    local seen = {}
-    for _, path in ipairs(paths) do
-      path = path:gsub("%/.jj/repo/store/type$", "")
-      path = path:gsub("%/.git/HEAD$", "")
-      if not seen[path] then
-        local item = {
-          path = path,
-          text = path:gsub("%" .. root .. "/", " "),
-        }
-        table.insert(result, item)
-        seen[path] = true
-      end
-    end
-    return result
-  end
-
-  local choose = function(item)
-    local_opts.cwd = item.path
-    vim.fn.chdir(item.path)
-    vim.schedule(function()
-      MiniPick.builtin.files(local_opts, { source = { cwd = item.path, tool = "rg" } })
-    end)
-  end
-
-  return MiniPick.builtin.cli({ command = command, postprocess = postprocess }, { source = { choose = choose } })
-end
-
 MiniPick.registry.files_root = function(local_opts)
   local root_patterns = { ".jj", ".git" }
   local root_dir = vim.fs.dirname(vim.fs.find(root_patterns, { upward = true })[1])
   local_opts.cwd = root_dir
   local_opts.tool = "rg"
-  return MiniPick.builtin.files(local_opts, { source = { cwd = root_dir, tool = "rg" } })
+  return MiniPick.builtin.files(local_opts, { source = { cwd = root_dir, tool = "ripgrep" } })
 end
-
 MiniPick.registry.grep_live_root = function(local_opts)
   local root_patterns = { ".jj", ".git" }
   local root_dir = vim.fs.dirname(vim.fs.find(root_patterns, { upward = true })[1])
@@ -128,56 +79,59 @@ MiniPick.registry.grep_live_root = function(local_opts)
 end
 
 require("mini.pick").registry.buffers = function(local_opts, opts)
-  local_opts = vim.tbl_deep_extend(
-    "force",
-    { sort_lastused = false, sort_mru = true, include_current = true, include_unlisted = false },
-    local_opts or {}
-  )
-  local buffers_output = vim.api.nvim_exec("buffers" .. (local_opts.include_unlisted and "!" or ""), true)
-  local cur_buf_id, include_current = vim.api.nvim_get_current_buf(), local_opts.include_current
-  local items = {}
-  local default_selection_idx = 1
-  for _, l in ipairs(vim.split(buffers_output, "\n")) do
-    local buf_str, name = l:match("^%s*%d+"), l:match('"(.*)"')
-    local buf_id = tonumber(buf_str)
-    local flag = buf_id == vim.fn.bufnr("") and "%" or (buf_id == vim.fn.bufnr("#") and "#" or " ")
-    local item = { text = name, bufnr = buf_id, flag = flag }
-    if buf_id ~= cur_buf_id or include_current then
-      if local_opts.sort_lastused and not local_opts.ignore_current_buffer and flag == "#" then
-        default_selection_idx = 2
-      end
-      if local_opts.sort_lastused and (flag == "#" or flag == "%") then
-        local idx = ((items[1] ~= nil and items[1].flag == "%") and 2 or 1)
-        table.insert(items, idx, item)
-      else
-        table.insert(items, item)
-      end
-    end
-  end
-  if local_opts.sort_mru then
-    table.sort(items, function(a, b)
-      return vim.fn.getbufinfo(a.bufnr)[1].lastused > vim.fn.getbufinfo(b.bufnr)[1].lastused
-    end)
-  end
+		local_opts = vim.tbl_deep_extend(
+			"force",
+			{ sort_lastused = false, sort_mru = true, include_current = true, include_unlisted = false },
+			local_opts or {}
+		)
+		local buffers_output = vim.api.nvim_exec("buffers" .. (local_opts.include_unlisted and "!" or ""), true)
+		local cur_buf_id, include_current = vim.api.nvim_get_current_buf(), local_opts.include_current
+		local items = {}
+		local default_selection_idx = 1
+		for _, l in ipairs(vim.split(buffers_output, "\n")) do
+			local buf_str, name = l:match("^%s*%d+"), l:match('"(.*)"')
+			local buf_id = tonumber(buf_str)
+			local flag = buf_id == vim.fn.bufnr("") and "%" or (buf_id == vim.fn.bufnr("#") and "#" or " ")
+			local item = { text = name, bufnr = buf_id, flag = flag }
+			if buf_id ~= cur_buf_id or include_current then
+				if local_opts.sort_lastused and not local_opts.ignore_current_buffer and flag == "#" then
+					default_selection_idx = 2
+				end
+				if local_opts.sort_lastused and (flag == "#" or flag == "%") then
+					local idx = ((items[1] ~= nil and items[1].flag == "%") and 2 or 1)
+					table.insert(items, idx, item)
+				else
+					table.insert(items, item)
+				end
+			end
+		end
+		if local_opts.sort_mru then
+			table.sort(items, function(a, b)
+				return vim.fn.getbufinfo(a.bufnr)[1].lastused > vim.fn.getbufinfo(b.bufnr)[1].lastused
+			end)
+		end
+
+		local show = function(buf_id, items, query)
+			require("mini.pick").default_show(buf_id, items, query, { show_icons = true })
+		end
+		local default_opts = { source = { name = "Buffers", show = show } }
+		opts = vim.tbl_deep_extend("force", default_opts, opts or {}, { source = { items = items } })
+		if default_selection_idx > 1 then
+			vim.api.nvim_create_autocmd("User", {
+				pattern = "MiniPickStart",
+				once = true,
+				callback = function()
+					local mappings = require("mini.pick").get_picker_opts().mappings
+					local keys = vim.fn["repeat"](mappings.move_down, default_selection_idx - 1)
+					vim.api.nvim_input(vim.api.nvim_replace_termcodes(keys, true, true, true))
+				end,
+			})
+		end
+		return require("mini.pick").start(opts)
+	end
+
+
 
-  local show = function(buf_id, items, query)
-    require("mini.pick").default_show(buf_id, items, query, { show_icons = true })
-  end
-  local default_opts = { source = { name = "Buffers", show = show } }
-  opts = vim.tbl_deep_extend("force", default_opts, opts or {}, { source = { items = items } })
-  if default_selection_idx > 1 then
-    vim.api.nvim_create_autocmd("User", {
-      pattern = "MiniPickStart",
-      once = true,
-      callback = function()
-        local mappings = require("mini.pick").get_picker_opts().mappings
-        local keys = vim.fn["repeat"](mappings.move_down, default_selection_idx - 1)
-        vim.api.nvim_input(vim.api.nvim_replace_termcodes(keys, true, true, true))
-      end,
-    })
-  end
-  return require("mini.pick").start(opts)
-end
 
 local miniclue = require('mini.clue')
 miniclue.setup({ -- cute prompts about bindings
@@ -248,14 +202,11 @@ require('mini.notify').setup({
 
 require('mini.starter').setup({
   header =
-  [[
-████████▄             ▄▄                      ▒▒
-██     ▀██            ██
-██     ▄██ ▄██████▄ ██████ ▄██████▄  ▄████▄██ ██ ▄██████▄
-████████▀  ▀▀    ██   ██   ▀▀    ██ ██▀   ▀██ ██ ▀▀    ██
-██         ▄███████   ██   ▄███████ ██     ██ ██ ▄███████
-██         ██    ██   ██   ██    ██ ██▄   ▄██ ██ ██    ██
-██         ▀████▀██   ▀███ ▀████▀██  ▀████▀██ ██ ▀████▀██
-                                    ▄▄     ██
-                                    ▀██████▀ ]]
+  [[ ______                      _
+(_____ \     _              (_)
+ _____) )___| |_  ____  ____ _  ____
+|  ____/ _  |  _)/ _  |/ _  | |/ _  |
+| |   ( ( | | |_( ( | ( ( | | ( ( | |
+|_|    \_||_|\___)_||_|\_|| |_|\_||_|
+                      (_____|]]
 })
diff --git a/home/common/nvim/rust.lua b/home/common/nvim/rust.lua
deleted file mode 100644
index 982daa7..0000000
--- a/home/common/nvim/rust.lua
+++ /dev/null
@@ -1,40 +0,0 @@
-vim.g.rustaceanvim = {
-  server = {
-    settings = {
-      ["rust-analyzer"] = {
-        inlayHints = {
-          bindingModeHints = {
-            enable = false,
-          },
-          chainingHints = {
-            enable = true,
-          },
-          closingBraceHints = {
-            enable = true,
-            minLines = 25,
-          },
-          closureReturnTypeHints = {
-            enable = "never",
-          },
-          lifetimeElisionHints = {
-            enable = "never",
-            useParameterNames = false,
-          },
-          maxLength = 25,
-          parameterHints = {
-            enable = true,
-          },
-          reborrowHints = {
-            enable = "never",
-          },
-          renderColons = true,
-          typeHints = {
-            enable = true,
-            hideClosureInitialization = false,
-            hideNamedConstructor = false,
-          },
-        },
-      },
-    },
-  },
-}
diff --git a/home/common/nvim/treesitter.nix b/home/common/nvim/treesitter.nix
index 25e15f8..4fb87ec 100644
--- a/home/common/nvim/treesitter.nix
+++ b/home/common/nvim/treesitter.nix
@@ -11,9 +11,8 @@
     ];
 
     plugins = with pkgs.vimPlugins; [
-      nvim-ts-context-commentstring
-      playground
       ts-comments-nvim
+      nvim-ts-context-commentstring
 
       {
         plugin = nvim-treesitter-context;
@@ -44,6 +43,20 @@
         '';
       }
 
+      {
+        plugin = pkgs.vimUtils.buildVimPlugin {
+          name = "nvim-tree-pairs"; # make % match in TS
+          src = pkgs.fetchFromGitHub {
+            owner = "yorickpeterse";
+            repo = "nvim-tree-pairs";
+            rev = "e7f7b6cc28dda6f3fa271ce63b0d371d5b7641da";
+            hash = "sha256-fb4EsrWAbm8+dWAhiirCPuR44MEg+KYb9hZOIuEuT24=";
+          };
+        };
+        type = "lua";
+        config = "require('tree-pairs').setup()";
+      }
+
       {
         plugin = nvim-treesitter-textobjects;
         type = "lua";
diff --git a/home/common/tmux.nix b/home/common/tmux.nix
index a587338..d5b0687 100644
--- a/home/common/tmux.nix
+++ b/home/common/tmux.nix
@@ -25,6 +25,7 @@
       set -g status-right '%F |  %R'
       set -g status off
       set -g update-environment "SSH_AUTH_SOCK"
+      setenv -g "SSH_AUTH_SOCK" "$XDG_RUNTIME_DIR/ssh-agent"
       setw -g alternate-screen on
       setw -g automatic-rename off
       setw -g window-status-format ""
@@ -33,15 +34,16 @@
 
       set -s command-alias[1000] stty='run-shell "tmux send-keys \"stty cols #{pane_width} rows #{pane_height}\" Enter"'
 
-      bind -n C-2 if-shell 'tmux select-window -t t1' refresh-client 'new-window -S -n t1'
-      bind -n C-3 if-shell 'tmux select-window -t t2' refresh-client 'new-window -S -n t2'
-      bind -n C-4 if-shell 'tmux select-window -t t3' refresh-client 'new-window -S -n t3'
-      bind -n C-5 if-shell 'tmux select-window -t t4' refresh-client 'new-window -S -n t4'
-      bind -n C-6 if-shell 'tmux select-window -t t5' refresh-client 'new-window -S -n t5'
-      bind -n C-7 if-shell 'tmux select-window -t t6' refresh-client 'new-window -S -n t6'
-      bind -n C-8 if-shell 'tmux select-window -t t7' refresh-client 'new-window -S -n t7'
-      bind -n C-9 if-shell 'tmux select-window -t t8' refresh-client 'new-window -S -n t8'
-      bind -n C-0 if-shell 'tmux select-window -t t9' refresh-client 'new-window -S -n t9'
+      bind -n M-1 if-shell 'tmux select-window -t nvim' refresh-client 'new-window -S -n nvim nvim --listen $XDG_RUNTIME_DIR/nvim-persistent.sock'
+      bind -n M-2 if-shell 'tmux select-window -t t1' refresh-client 'new-window -S -n t1'
+      bind -n M-3 if-shell 'tmux select-window -t t2' refresh-client 'new-window -S -n t2'
+      bind -n M-4 if-shell 'tmux select-window -t t3' refresh-client 'new-window -S -n t3'
+      bind -n M-5 if-shell 'tmux select-window -t t4' refresh-client 'new-window -S -n t4'
+      bind -n M-6 if-shell 'tmux select-window -t t5' refresh-client 'new-window -S -n t5'
+      bind -n M-7 if-shell 'tmux select-window -t t6' refresh-client 'new-window -S -n t6'
+      bind -n M-8 if-shell 'tmux select-window -t t7' refresh-client 'new-window -S -n t7'
+      bind -n M-9 if-shell 'tmux select-window -t t8' refresh-client 'new-window -S -n t8'
+      bind -n M-0 if-shell 'tmux select-window -t t9' refresh-client 'new-window -S -n t9'
       bind -T copy-mode-vi WheelUpPane select-pane \; send-keys -X -N 1 scroll-up
       bind -T copy-mode-vi WheelDownPane select-pane \; send-keys -X -N 1 scroll-down
       bind C-s set-option -g status
diff --git a/home/common/utils.nix b/home/common/utils.nix
index ff902b9..0a608da 100644
--- a/home/common/utils.nix
+++ b/home/common/utils.nix
@@ -1,14 +1,13 @@
 { pkgs, ... }:
 {
   home.packages = with pkgs; [
+    grc
     dust
     jless
     procs
     viddy
   ];
 
-  home.sessionVariables.DIRENV_LOG_FORMAT = ''$(printf "\033[2mdirenv: %%s\033[0m")'';
-
   programs = {
     bat = {
       enable = true;
@@ -34,6 +33,11 @@
       };
     };
 
+    eza = {
+      enable = true;
+      enableFishIntegration = true;
+    };
+
     fd.enable = true;
 
     fzf = {
@@ -49,29 +53,17 @@
     ripgrep = {
       enable = true;
       arguments = [
-        "--glob=!**/.cache/*"
-        "--glob=!**/.direnv/*"
-        "--glob=!**/.git/*"
-        "--glob=!**/.jj/*"
-        "--glob=!**/{node_modules,.npm,dist}/*"
-        "--glob=!**/target/*"
-        "--glob=!**/result/*"
+        "--glob=!.git/*"
+        "--glob=!.jj/*"
+        "--glob=!result/*"
+        "--glob=!target/*"
       ];
     };
 
+    zoxide = {
+      enable = true;
+      enableFishIntegration = true;
+      options = [ "--cmd=cd" ];
+    };
   };
-
-  programs.eza = {
-    enable = true;
-    enableFishIntegration = true;
-  };
-  home.sessionVariables.EZA_COLORS = "reset:oc=0:ur=0:uw=0:ux=0:ue=0:gr=0:gw=0:gx=0:tr=0:tw=0:tx=0:su=0:sf=0:xa=0:sn=0:nb=0:nk=0:nm=0:ng=0:nt=0:sb=0:ub=0:uk=0:um=0:ug=0:ut=0:df=0:ds=0:uu=0:uR=0:un=0:gu=0:gR=0:gn=0:lc=0:lm=0:ga=0:gm=0:gd=0:gv=0:gt=0:gi=0:gc=0:Gm=0:Go=0:Gc=0:Gd=0:xx=0:da=0:in=0:bl=0:hd=0:lp=4:cc=0:bO=0:sp=0:mp=0:im=0:vi=0:mu=0:lo=0:cr=0:do=0:co=0:tm=0:cm=0:bu=0:sc=0:ic=0:Sn=0:Su=0:Sr=0:St=0:Sl=0:ff=0:di=1:ex=0:fi=0:pi=0:so=0:bd=0:cd=0:ln=4:or=4";
-
-  programs.zoxide = {
-    enable = true;
-    enableFishIntegration = true;
-    options = [ "--cmd=cd" ];
-  };
-  home.sessionVariables._ZO_FZF_OPTS = "--reverse --height=10 --border=rounded --no-info --no-separator --no-scrollbar --no-color --no-sort";
-
 }
diff --git a/home/common/vcs.nix b/home/common/vcs.nix
index bc74bb3..fde4105 100644
--- a/home/common/vcs.nix
+++ b/home/common/vcs.nix
@@ -1,9 +1,4 @@
-{
-  config,
-  inputs,
-  pkgs,
-  ...
-}:
+{ config, pkgs, ... }:
 {
 
   home.packages = with pkgs; [
@@ -12,6 +7,7 @@
     difftastic
     git-get
     git-graph
+    lazyjj
     tea
   ];
 
@@ -120,12 +116,9 @@
       "*.so"
       "*.swp"
       ".direnv"
-      ".env"
       ".idea"
-      ".nixos-test-history"
       ".null-ls_*"
-      "/result*"
-      "/target"
+      "result"
     ];
 
     signing = {
@@ -134,7 +127,45 @@
     };
   };
 
+  programs.gitui = {
+    enable = true;
+    keyConfig = ''
+      (
+       open_help: Some(( code: F(1), modifiers: "")),
+       move_left: Some(( code: Char('h'), modifiers: "")),
+       move_right: Some(( code: Char('l'), modifiers: "")),
+       move_up: Some(( code: Char('k'), modifiers: "")),
+       move_down: Some(( code: Char('j'), modifiers: "")),
+       popup_up: Some(( code: Char('p'), modifiers: "CONTROL")),
+       popup_down: Some(( code: Char('n'), modifiers: "CONTROL")),
+       page_up: Some(( code: Char('b'), modifiers: "CONTROL")),
+       page_down: Some(( code: Char('f'), modifiers: "CONTROL")),
+       home: Some(( code: Char('g'), modifiers: "")),
+       end: Some(( code: Char('G'), modifiers: "SHIFT")),
+       shift_up: Some(( code: Char('K'), modifiers: "SHIFT")),
+       shift_down: Some(( code: Char('J'), modifiers: "SHIFT")),
+       edit_file: Some(( code: Char('I'), modifiers: "SHIFT")),
+       status_reset_item: Some(( code: Char('U'), modifiers: "SHIFT")),
+       diff_reset_lines: Some(( code: Char('u'), modifiers: "")),
+       diff_stage_lines: Some(( code: Char('s'), modifiers: "")),
+       stashing_save: Some(( code: Char('w'), modifiers: "")),
+       stashing_toggle_index: Some(( code: Char('m'), modifiers: "")),
+       stash_open: Some(( code: Char('l'), modifiers: "")),
+       abort_merge: Some(( code: Char('M'), modifiers: "SHIFT")),
+       )
+      	 '';
+    theme = ''
+      (
+       selection_bg: Some(Black),
+       selection_fg: Some(Reset),
+       cmdbar_bg: Some(Reset),
+       cmdbar_extra_lines_bg: Some(Reset),
+      )
+    '';
+  };
+
   programs.jujutsu = {
     enable = true;
+    package = pkgs.jujutsu-openssh;
   };
 }
diff --git a/home/common/wezterm.nix b/home/common/wezterm.nix
deleted file mode 100644
index 121b8ca..0000000
--- a/home/common/wezterm.nix
+++ /dev/null
@@ -1,72 +0,0 @@
-{
-  config,
-  lib,
-  ...
-}:
-{
-  config = lib.mkIf config.patagia.desktop.enable {
-    programs.wezterm = {
-      enable = true;
-      colorSchemes = {
-        patagiaLight = {
-          ansi = [
-            "#222222"
-            "#D14949"
-            "#48874F"
-            "#AFA75A"
-            "#599797"
-            "#8F6089"
-            "#5C9FA8"
-            "#8C8C8C"
-          ];
-          brights = [
-            "#444444"
-            "#FF6D6D"
-            "#89FF95"
-            "#FFF484"
-            "#97DDFF"
-            "#FDAAF2"
-            "#85F5DA"
-            "#E9E9E9"
-          ];
-          background = "#fefeff";
-          foreground = "#222222";
-          cursor_bg = "#aa0000";
-          cursor_border = "#aa0000";
-          cursor_fg = "#1B1B1B";
-          selection_bg = "#ffe6a4";
-          selection_fg = "#483600";
-        };
-      };
-
-      extraConfig = ''
-        return {
-          font = wezterm.font("Berkeley Mono", { weight = "Regular", stretch = "Normal" }),
-          font_size = 16,
-          -- freetype_load_target = "HorizontalLcd",
-          freetype_load_target = "Light",
-          -- font_size = 11,
-          -- font_size = 11,
-          -- freetype_load_target = "Normal",
-          freetype_load_flags = "NO_AUTOHINT",
-          color_scheme = "patagiaLight",
-          check_for_updates = false,
-          custom_block_glyphs = false,
-          warn_about_missing_glyphs = false,
-          bold_brightens_ansi_colors = false,
-          unicode_version = 14,
-          allow_square_glyphs_to_overflow_width = "Always",
-          xcursor_theme = "Adwaita",
-          hide_mouse_cursor_when_typing = false,
-          tab_bar_at_bottom = true,
-          use_fancy_tab_bar = false,
-          show_tab_index_in_tab_bar = true,
-          underline_position = -4,
-          underline_thickness = 2,
-          --line_height = 0.95,
-        }
-      '';
-
-    };
-  };
-}
diff --git a/home/dln/desktop.nix b/home/dln/desktop.nix
index 0ef0500..ae7ded3 100644
--- a/home/dln/desktop.nix
+++ b/home/dln/desktop.nix
@@ -1,4 +1,4 @@
-{ pkgs, ... }:
+{ inputs, pkgs, ... }:
 {
   patagia = {
     desktop.enable = true;
@@ -7,17 +7,15 @@
   home.packages = with pkgs; [
     cameractrls-gtk4
     dynamic-wallpaper
-    gimp
-    gimpPlugins.bimp
+    gimp-with-plugins
     inkscape
-    libreoffice
+    inputs.ghostty.packages.${pkgs.system}.default
     moonlight-qt
     obsidian
     pavucontrol
     plexamp
     signal-desktop
-    spotify
-    thunderbird
+    zed-editor
   ];
 
   xdg.desktopEntries = {
diff --git a/home/dln/dinky.nix b/home/dln/dinky.nix
index b0b76b0..ba0b79e 100644
--- a/home/dln/dinky.nix
+++ b/home/dln/dinky.nix
@@ -5,9 +5,10 @@
     ./desktop.nix
   ];
 
-  patagia = {
-    laptop.enable = true;
-    oled.enable = true;
+  dconf.settings = {
+    "org/gnome/shell" = {
+      enabled-extensions = [ "Battery-Health-Charging@maniacx.github.com" ];
+    };
   };
 
   home.packages = with pkgs; [ ];
@@ -15,6 +16,6 @@
   programs.gpg.enable = true;
   services.gpg-agent = {
     enable = true;
-    pinentry.package = pkgs.pinentry-curses;
+    pinentryPackage = pkgs.pinentry-curses;
   };
 }
diff --git a/home/dln/home.nix b/home/dln/home.nix
index 26216e7..4ec8164 100644
--- a/home/dln/home.nix
+++ b/home/dln/home.nix
@@ -1,9 +1,4 @@
-{
-  config,
-  lib,
-  pkgs,
-  ...
-}:
+{ config, pkgs, ... }:
 let
   realName = "Daniel Lundin";
   email = "dln@arity.se";
@@ -14,8 +9,8 @@ in
     homeDirectory = "/home/dln";
     packages = with pkgs; [
       asciinema
+      openconnect
       ouch
-      toolbox
     ];
   };
 
@@ -43,6 +38,7 @@ in
 
   programs.helix = {
     enable = true;
+    # extraPackages = [];
   };
 
   programs.jujutsu = {
@@ -53,7 +49,7 @@ in
       };
 
       signing = {
-        behavior = "own";
+        sign-all = true;
         backend = "ssh";
         backends.ssh.allowed-signers = "/home/dln/.ssh/authorized_keys";
         key = "/home/dln/.ssh/git_signing_key.pub";
@@ -64,13 +60,19 @@ in
       };
 
       ui = {
-        "default-command" = [ "s" ];
+        "default-command" = [
+          "log"
+          "--limit=10"
+          "-T"
+          "builtin_log_comfortable"
+        ];
         pager = "delta";
       };
 
       "merge-tools" = {
         difft."diff-args" = [
           "--color=always"
+          "--missing-as-empty"
           "$left"
           "$right"
         ];
@@ -79,6 +81,7 @@ in
           "diff-args" = [
             "--color=always"
             "--display=inline"
+            "--missing-as-empty"
             "$left"
             "$right"
           ];
@@ -104,35 +107,23 @@ in
         ];
         d = [
           "diff"
-          "--tool=difft"
+          "--tool=difftu"
         ];
         dd = [
           "diff"
           "--git"
         ];
-        du = [
+        ds = [
           "diff"
-          "--tool=difftu"
+          "--tool=difft"
         ];
         s = [
-          "util"
-          "exec"
-          "--"
-          "bash"
-          "-c"
-          ''
-            #!/usr/bin/env bash
-            set -eo pipefail
-            printf '\e[38;5;240m\u2504%.0s\e[0m' $(seq 1 $(tput cols)) '\n'
-            jj show --stat
-            printf '\e[38;5;240m\u2504%.0s\e[0m' $(seq 1 $(tput cols)) '\n'
-            if [ -n "$1" ]; then
-              jj diff --tool=difft -r "$@"
-            else
-              jj log --limit=15 -T builtin_log_comfortable
-            fi
-          ''
-          ""
+          "show"
+          "--tool=difftu"
+        ];
+        ss = [
+          "show"
+          "--tool=difft"
         ];
       };
 
@@ -145,137 +136,26 @@ in
         "ready" = "open() ~ (wip::)";
       };
 
-      colors =
-        let
-          bold = {
-            bold = true;
-          };
-          dim = {
-            fg = "bright black";
-          };
-          underline = {
-            fg = "default";
-            underline = true;
-          };
-        in
-        {
-          "error" = bold;
-          "warning" = bold;
-          "error heading" = bold;
-          "error_source heading" = bold;
-          "warning heading" = bold;
-          "hint heading" = bold;
-          "prefix" = bold;
-          "rest" = "bright black";
-          "divergent prefix" = underline;
-          "bookmark" = "bright magenta";
-          "bookmarks" = "bright magenta";
-          "change_id" = "bright magenta";
-          "local_bookmarks" = "bright magenta";
+      colors = {
+        "commit_id prefix" = {
+          bold = true;
+        };
 
-          "diff file_header" = bold;
-          "diff hunk_header" = "cyan";
-          "diff removed" = "red";
-          "diff removed token" = "red";
-          "diff added" = "green";
-          "diff added token" = "green";
-          "diff modified" = "cyan";
-          "diff untracked" = "blue";
-          "diff renamed" = "cyan";
-          "diff copied" = "green";
-          "diff access-denied" = {
-            bg = "red";
-          };
-
-          "empty" = "green";
-          "elided" = "blue";
-          "node elided" = dim;
-          "node working_copy" = {
-            fg = "green";
-            bold = true;
-          };
-          "node current_operation" = bold;
-          "node immutable" = bold;
-          "node conflict" = {
-            fg = "red";
-            bold = true;
-          };
-          "operation id" = "blue";
-          "operation current_operation" = bold;
-          "remote_bookmarks" = "bright magenta";
-          "working_copy" = {
-            fg = "green";
-            bold = true;
-          };
-          "working_copy empty" = {
-            fg = "green";
-            bold = true;
-          };
-          "working_copy change_id" = "bright magenta";
-          "working_copy description placeholder" = "green";
-          "working_copy empty description placeholder" = "green";
-          "working_copy bookmark" = "bright magenta";
-          "working_copy bookmarks" = "bright magenta";
-          "working_copy local_bookmarks" = "bright magenta";
-          "working_copy remote_bookmarks" = "bright magenta";
-        }
-        // lib.genAttrs [
-          "author"
-          "branch"
-          "branches"
-          "commit_id"
-          "committer"
-          "config_list name"
-          "config_list overridden"
-          "config_list overridden name"
-          "config_list overridden value"
-          "config_list value"
-          "conflict"
-          "conflict_description"
-          "conflict_description difficult"
-          "description placeholder"
-          "diff token"
-          "divergent"
-          "divergent change_id"
-          "divergent rest"
-          "empty description placeholder"
-          "error_source"
-          "git_head"
-          "git_refs"
-          "hidden prefix"
-          "hint"
-          "local_branches"
-          "operation current_operation id"
-          "operation current_operation time"
-          "operation current_operation user"
-          "operation time"
-          "operation user"
-          "placeholder"
-          "remote_branches"
-          "root"
-          "separator"
-          "tag"
-          "tags"
-          "timestamp"
-          "working_copies"
-          "working_copy author"
-          "working_copy branch"
-          "working_copy branches"
-          "working_copy commit_id"
-          "working_copy committer"
-          "working_copy conflict"
-          "working_copy divergent"
-          "working_copy divergent change_id"
-          "working_copy git_refs"
-          "working_copy local_branches"
-          "working_copy placeholder"
-          "working_copy remote_branches"
-          "working_copy tag"
-          "working_copy tags"
-          "working_copy timestamp"
-          "working_copy working_copies"
-        ] (_: "default");
+        "rest" = {
+          fg = "bright black";
+          bold = false;
+        };
 
+        "diff added token" = {
+          bg = "#002200";
+          fg = "#66ffcc";
+          underline = false;
+        };
+        "diff removed token" = {
+          bg = "#220011";
+          underline = true;
+        };
+      };
     };
   };
 
@@ -284,12 +164,12 @@ in
   '';
 
   programs.ssh.matchBlocks = {
-    dev-old = {
+    dev = {
       hostname = "10.1.100.16";
       forwardAgent = true;
     };
 
-    devel = {
+    nemo = {
       hostname = "10.1.100.20";
       forwardAgent = true;
       localForwards = [
diff --git a/home/dln/nemo.nix b/home/dln/nemo.nix
index cffb9ca..1c38f16 100644
--- a/home/dln/nemo.nix
+++ b/home/dln/nemo.nix
@@ -6,7 +6,7 @@
   ];
 
   programs.ghostty.settings = {
-    font-size = lib.mkForce 15;
+    font-size = lib.mkForce 18;
   };
 
   programs.obs-studio = {
@@ -24,17 +24,13 @@
     };
   };
 
-  home.packages = with pkgs; [
-    endeavour
-    picard
-    stable.calibre
-  ];
+  home.packages = with pkgs; [ stable.calibre ];
 
   programs.gpg.enable = true;
 
   services.gpg-agent = {
     enable = true;
     enableScDaemon = false;
-    pinentry.package = pkgs.pinentry-curses;
+    pinentryPackage = pkgs.pinentry-curses;
   };
 }
diff --git a/home/lsjostro/home.nix b/home/lsjostro/home.nix
new file mode 100644
index 0000000..f1d8a4d
--- /dev/null
+++ b/home/lsjostro/home.nix
@@ -0,0 +1,40 @@
+{ pkgs, ... }:
+{
+  home = {
+    username = "lsjostro";
+    homeDirectory = "/home/lsjostro";
+    packages = with pkgs; [ openconnect ];
+  };
+
+  programs.git = {
+    userName = "Lars Sjöstrom";
+    userEmail = "lars@radicore.se";
+  };
+
+  programs.ssh.matchBlocks = {
+    dev = {
+      hostname = "10.1.100.17";
+    };
+
+    nemo = {
+      hostname = "10.1.100.20";
+      forwardAgent = true;
+      localForwards = [
+        {
+          bind.address = "localhost";
+          bind.port = 8000;
+          host.address = "localhost";
+          host.port = 8000;
+        }
+        {
+          bind.address = "localhost";
+          bind.port = 8080;
+          host.address = "localhost";
+          host.port = 8080;
+        }
+      ];
+    };
+  };
+
+  home.stateVersion = "24.05"; # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
+}
diff --git a/home/lsjostro/nemo.nix b/home/lsjostro/nemo.nix
new file mode 100644
index 0000000..0de2f39
--- /dev/null
+++ b/home/lsjostro/nemo.nix
@@ -0,0 +1,6 @@
+{ ... }:
+{
+  imports = [ ./home.nix ];
+
+  # Host specific user config goes here
+}
diff --git a/hosts/dinky/default.nix b/hosts/dinky/default.nix
index 058294d..90f6d5a 100644
--- a/hosts/dinky/default.nix
+++ b/hosts/dinky/default.nix
@@ -78,10 +78,10 @@
 
   networking = {
     hostName = "dinky";
-    domain = "aarn.patagia.net";
+    domain = "aarn.patagia.dev";
     search = [
-      "patagia.net"
-      "aarn.patagia.net"
+      "patagia.dev"
+      "aarn.patagia.dev"
     ];
     useDHCP = lib.mkDefault true;
   };
@@ -120,7 +120,7 @@
   nix.settings.trusted-users = [ "dln" ];
   nix.buildMachines = [
     {
-      hostName = "nemo.aarn.patagia.net";
+      hostName = "nemo.aarn.patagia.dev";
       sshUser = "nixremote";
       sshKey = "/root/.ssh/id_ed25519";
       system = "x86_64-linux";
@@ -138,8 +138,8 @@
   nix.distributedBuilds = true;
   nix.settings.builders-use-substitutes = true;
   nix.settings.trusted-substituters = [
-    "ssh-ng://nemo.aarn.patagia.net"
+    "ssh-ng://nemo.aarn.patagia.dev"
   ];
 
-  system.stateVersion = "25.05"; # Did you read the comment?
+  system.stateVersion = "24.05"; # Did you read the comment?
 }
diff --git a/hosts/nemo/default.nix b/hosts/nemo/default.nix
index 7f7c70c..ada8496 100644
--- a/hosts/nemo/default.nix
+++ b/hosts/nemo/default.nix
@@ -87,7 +87,7 @@
 
   networking = {
     hostName = "nemo"; # Define your hostname.
-    domain = "aarn.patagia.net";
+    domain = "aarn.patagia.dev";
     nameservers = [
       "10.1.100.11"
       "10.1.100.12"
@@ -117,33 +117,34 @@
 
   systemd.network.enable = true;
   systemd.network.networks."10-wifi" = {
-    matchConfig.Name = "wlan0";
+    matchConfig.Name = "wlan1";
     address = [ "10.1.100.20/22" ];
     gateway = [ "10.1.100.1" ];
     linkConfig.RequiredForOnline = "routable";
   };
 
   # FIXME: pam_rssh is broken from rust 1.80 upgrade
-  security = {
-    pam.services.doas =
-      { config, ... }:
-      {
-        rules.auth.rssh = {
-          order = config.rules.auth.ssh_agent_auth.order - 1;
-          control = "sufficient";
-          modulePath = "${pkgs.pam_rssh}/lib/libpam_rssh.so";
-          settings.authorized_keys_command = pkgs.writeShellScript "get-authorized-keys" ''
-            cat "/etc/ssh/authorized_keys.d/$1"
-          '';
-        };
-      };
-  };
+  # environment.systemPackages = [ pkgs.pam_rssh ];
+  # security = {
+  #   pam.services.doas =
+  #     { config, ... }:
+  #     {
+  #       rules.auth.rssh = {
+  #         order = config.rules.auth.ssh_agent_auth.order - 1;
+  #         control = "sufficient";
+  #         modulePath = "${pkgs.pam_rssh}/lib/libpam_rssh.so";
+  #         settings.authorized_keys_command = pkgs.writeShellScript "get-authorized-keys" ''
+  #           cat "/etc/ssh/authorized_keys.d/$1"
+  #         '';
+  #       };
+  #     };
+  # };
 
   services.resolved = {
     enable = true;
     domains = [
-      "patagia.net"
-      "aarn.patagia.net"
+      "patagia.dev"
+      "aarn.patagia.dev"
     ];
     llmnr = "false";
     fallbackDns = [ "9.9.9.9" ];
@@ -158,6 +159,12 @@
     };
   };
 
+  services.sunshine = {
+    enable = true;
+    openFirewall = true;
+    settings = { };
+  };
+
   patagia = {
     desktop.enable = true;
     plymouth.enable = true;
@@ -168,29 +175,17 @@
     ffado
     libcamera
     lm_sensors
-    pam_rssh
+    # pkgs.pam_rssh
     openconnect
-    tpm2-tools
     v4l-utils
   ];
 
-  environment.variables = {
-    OTEL_EXPORTER_OTLP_ENDPOINT = "https://otel.aarn.patagia.net";
-  };
-
-  security.tpm2 = {
-    enable = true;
-    pkcs11.enable = true;
-    tctiEnvironment.enable = true;
-  };
+  programs.coolercontrol.enable = true;
 
   users.users.dln = {
     isNormalUser = true;
     description = "Daniel Lundin";
-    extraGroups = [
-      "tss"
-      "wheel"
-    ];
+    extraGroups = [ "wheel" ];
     openssh.authorizedKeys.keys = [
       "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIHMAEZx02kbHrEygyPQYStiXlrIe6EIqBCv7anIkL0pAAAABHNzaDo= dln@dinky"
       "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJNOBFoU7Cdsgi4KpYRcv7EhR/8kD4DYjEZnwk6urRx7AAAABHNzaDo= dln@nemo"
@@ -200,10 +195,7 @@
   users.users.lsjostro = {
     isNormalUser = true;
     description = "Lars Sjöström";
-    extraGroups = [
-      "tss"
-      "wheel"
-    ];
+    extraGroups = [ "wheel" ];
     openssh.authorizedKeys.keys = [
       "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBJ10mLOpInoqDaySyrxbzvcOrJfLw48Y6eWHa9501lw+hEEBXya3ib7nlvpCqEQJ8aPU5fVRqpkOW5zSimCiRbwAAAAEc3NoOg=="
       "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBLpoKvsZDIQQLfgzJhe1jAQubBNxjydkj8UfdUPaSXqgfB02OypMOC1m5ZuJYcQIxox0I+4Z8xstFhYP6s8zKZwAAAAEc3NoOg=="
@@ -221,22 +213,11 @@
   };
   users.groups.nixremote = { };
 
-  nix.sshServe.enable = true;
-  nix.sshServe.keys = [
-    "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIHMAEZx02kbHrEygyPQYStiXlrIe6EIqBCv7anIkL0pAAAABHNzaDo= dln@dinky"
-    "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJNOBFoU7Cdsgi4KpYRcv7EhR/8kD4DYjEZnwk6urRx7AAAABHNzaDo= dln@nemo"
-    "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBJ10mLOpInoqDaySyrxbzvcOrJfLw48Y6eWHa9501lw+hEEBXya3ib7nlvpCqEQJ8aPU5fVRqpkOW5zSimCiRbwAAAAEc3NoOg=="
-    "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBLpoKvsZDIQQLfgzJhe1jAQubBNxjydkj8UfdUPaSXqgfB02OypMOC1m5ZuJYcQIxox0I+4Z8xstFhYP6s8zKZwAAAAEc3NoOg=="
-  ];
-
   nix.settings.trusted-users = [
     "dln"
     "lsjostro"
     "nixremote"
   ];
 
-  services.printing.enable = lib.mkForce true;
-  services.printing.drivers = [ pkgs.brlaser ];
-
-  system.stateVersion = "24.11"; # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
+  system.stateVersion = "24.05"; # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
 }
diff --git a/hosts/nemo/woodpecker.nix b/hosts/nemo/woodpecker.nix
index f3cd5ec..8a4e963 100644
--- a/hosts/nemo/woodpecker.nix
+++ b/hosts/nemo/woodpecker.nix
@@ -4,20 +4,6 @@
   ...
 }:
 {
-
-  users.users.woodpecker = {
-    isSystemUser = true;
-    group = "woodpecker";
-    extraGroups = [
-      "docker"
-      "podman"
-    ];
-    createHome = true;
-    home = "/etc/woodpecker";
-    homeMode = "764";
-  };
-  users.groups.woodpecker = { };
-
   services.woodpecker-agents.agents.docker = {
     enable = true;
     package = pkgs.woodpecker-agent;
@@ -41,11 +27,7 @@
     ];
     # restartIfChanged = false;
     serviceConfig = {
-      User = "woodpecker";
-      Group = "woodpecker";
-      WorkingDirectory = "/etc/woodpecker";
       BindPaths = [ "/run/podman/podman.sock" ];
     };
   };
-
 }
diff --git a/hosts/pearl/default.nix b/hosts/pearl/default.nix
index 4696113..a44a372 100644
--- a/hosts/pearl/default.nix
+++ b/hosts/pearl/default.nix
@@ -33,10 +33,10 @@
 
   networking = {
     hostName = "pearl";
-    domain = "aarn.patagia.net";
+    domain = "aarn.patagia.dev";
     search = [
       "patagia.dev"
-      "aarn.patagia.net"
+      "aarn.patagia.dev"
     ];
     useDHCP = lib.mkDefault true;
   };
@@ -99,7 +99,7 @@
   console.keyMap = "sv-latin1";
 
   # Enable sound with pipewire.
-  services.pulseaudio.enable = false;
+  hardware.pulseaudio.enable = false;
   security.rtkit.enable = true;
   services.pipewire = {
     enable = true;
diff --git a/justfile b/justfile
index ccf14df..75763bf 100644
--- a/justfile
+++ b/justfile
@@ -4,6 +4,9 @@ set shell := ["/usr/bin/env", "bash", "-euo", "pipefail", "-c"]
 default:
 	@just --list
 
+boot:
+  nh os boot .
+
 build:
   nh os build .
 
diff --git a/overlays/default.nix b/overlays/default.nix
index 61457f5..9dd6924 100644
--- a/overlays/default.nix
+++ b/overlays/default.nix
@@ -7,9 +7,7 @@
 
     # https://discourse.nixos.org/t/disable-ssh-agent-from-gnome-keyring-on-gnome/28176/5
     gnome-keyring = prev.gnome-keyring.overrideAttrs (oldAttrs: {
-      mesonFlags = (builtins.filter (flag: flag != "-Dssh-agent=true") oldAttrs.mesonFlags) ++ [
-        "-Dssh-agent=false"
-      ];
+      configureFlags = oldAttrs.configureFlags or [ ] ++ [ "--disable-ssh-agent" ];
     });
   };
 
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 3d0d4d6..ab3485b 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -1,3 +1,5 @@
 pkgs: {
   gnome-ssh-askpass4 = pkgs.callPackage ./gnome-ssh-askpass4 { };
+  jujutsu-openssh = pkgs.callPackage ./jujutsu-openssh { };
+  lazyjj = pkgs.callPackage ./lazyjj { };
 }
diff --git a/pkgs/jujutsu-openssh/Cargo.lock b/pkgs/jujutsu-openssh/Cargo.lock
new file mode 100644
index 0000000..f9d6918
--- /dev/null
+++ b/pkgs/jujutsu-openssh/Cargo.lock
@@ -0,0 +1,3828 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "adler2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "getrandom",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
+
+[[package]]
+name = "anstream"
+version = "0.6.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
+
+[[package]]
+name = "arc-swap"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "assert_cmd"
+version = "2.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d"
+dependencies = [
+ "anstyle",
+ "bstr",
+ "doc-comment",
+ "libc",
+ "predicates",
+ "predicates-core",
+ "predicates-tree",
+ "wait-timeout",
+]
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "async-trait"
+version = "0.1.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "backoff"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1"
+dependencies = [
+ "getrandom",
+ "instant",
+ "rand",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.73"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide 0.7.4",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
+[[package]]
+name = "blake2"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bstr"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
+dependencies = [
+ "memchr",
+ "regex-automata 0.4.8",
+ "serde",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "cast"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
+
+[[package]]
+name = "castaway"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "cc"
+version = "1.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9d013ecb737093c0e86b151a7b837993cf9ec6c502946cfb44bedc392421e0b"
+dependencies = [
+ "jobserver",
+ "libc",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "chrono-english"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f73d909da7eb4a7d88c679c3f5a1bc09d965754e0adb2e7627426cef96a00d6f"
+dependencies = [
+ "chrono",
+ "scanlex",
+]
+
+[[package]]
+name = "ciborium"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
+dependencies = [
+ "ciborium-io",
+ "ciborium-ll",
+ "serde",
+]
+
+[[package]]
+name = "ciborium-io"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
+
+[[package]]
+name = "ciborium-ll"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
+dependencies = [
+ "ciborium-io",
+ "half",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap-markdown"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ebc67e6266e14f8b31541c2f204724fa2ac7ad5c17d6f5908fbb92a60f42cff"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+ "terminal_size",
+]
+
+[[package]]
+name = "clap_complete"
+version = "4.5.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11611dca53440593f38e6b25ec629de50b14cdfa63adc0fb856115a2c6d97595"
+dependencies = [
+ "clap",
+]
+
+[[package]]
+name = "clap_complete_nushell"
+version = "4.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "315902e790cc6e5ddd20cbd313c1d0d49db77f191e149f96397230fb82a17677"
+dependencies = [
+ "clap",
+ "clap_complete",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+
+[[package]]
+name = "clap_mangen"
+version = "0.2.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f17415fd4dfbea46e3274fcd8d368284519b358654772afb700dc2e8d2b24eeb"
+dependencies = [
+ "clap",
+ "roff",
+]
+
+[[package]]
+name = "clru"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbd0f76e066e64fdc5631e3bb46381254deab9ef1158292f27c8c57e3bf3fe59"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+
+[[package]]
+name = "compact_str"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "ryu",
+ "static_assertions",
+]
+
+[[package]]
+name = "config"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23738e11972c7643e4ec947840fc463b6a571afcd3e735bdfce7d03c7a784aca"
+dependencies = [
+ "async-trait",
+ "lazy_static",
+ "nom",
+ "pathdiff",
+ "serde",
+ "toml",
+]
+
+[[package]]
+name = "console"
+version = "0.15.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "criterion"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
+dependencies = [
+ "anes",
+ "cast",
+ "ciborium",
+ "clap",
+ "criterion-plot",
+ "is-terminal",
+ "itertools 0.10.5",
+ "num-traits",
+ "once_cell",
+ "oorandom",
+ "plotters",
+ "rayon",
+ "regex",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "tinytemplate",
+ "walkdir",
+]
+
+[[package]]
+name = "criterion-plot"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
+dependencies = [
+ "cast",
+ "itertools 0.10.5",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crossterm"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
+dependencies = [
+ "bitflags 2.6.0",
+ "crossterm_winapi",
+ "libc",
+ "mio 0.8.11",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "dashmap"
+version = "6.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "diff"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
+
+[[package]]
+name = "difflib"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dirs"
+version = "5.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "esl01-renderdag"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a1840969ab8be31e186bb6d2f672d586dcd203dd4019a80dc1277a14686eca9"
+dependencies = [
+ "bitflags 1.3.2",
+ "itertools 0.10.5",
+]
+
+[[package]]
+name = "faster-hex"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
+
+[[package]]
+name = "fastrand"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
+
+[[package]]
+name = "filetime"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "libredox",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "fixedbitset"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
+
+[[package]]
+name = "flate2"
+version = "1.0.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide 0.8.0",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures 0.1.31",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "gen-protos"
+version = "0.23.0"
+dependencies = [
+ "prost-build",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "gimli"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
+
+[[package]]
+name = "git2"
+version = "0.19.0"
+source = "git+https://github.com/bnjmnt4n/git2-rs.git?rev=60e29ff0d#60e29ff0d84cdffd9f366455d32606e582a4c378"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "openssl-probe",
+ "openssl-sys",
+ "url",
+]
+
+[[package]]
+name = "gix"
+version = "0.66.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9048b8d1ae2104f045cb37e5c450fc49d5d8af22609386bfc739c11ba88995eb"
+dependencies = [
+ "gix-actor",
+ "gix-attributes",
+ "gix-command",
+ "gix-commitgraph",
+ "gix-config",
+ "gix-date",
+ "gix-diff",
+ "gix-discover",
+ "gix-features",
+ "gix-filter",
+ "gix-fs",
+ "gix-glob",
+ "gix-hash",
+ "gix-hashtable",
+ "gix-ignore",
+ "gix-index",
+ "gix-lock",
+ "gix-object",
+ "gix-odb",
+ "gix-pack",
+ "gix-path",
+ "gix-pathspec",
+ "gix-ref",
+ "gix-refspec",
+ "gix-revision",
+ "gix-revwalk",
+ "gix-sec",
+ "gix-submodule",
+ "gix-tempfile",
+ "gix-trace",
+ "gix-traverse",
+ "gix-url",
+ "gix-utils",
+ "gix-validate",
+ "gix-worktree",
+ "once_cell",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-actor"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc19e312cd45c4a66cd003f909163dc2f8e1623e30a0c0c6df3776e89b308665"
+dependencies = [
+ "bstr",
+ "gix-date",
+ "gix-utils",
+ "itoa",
+ "thiserror",
+ "winnow 0.6.18",
+]
+
+[[package]]
+name = "gix-attributes"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebccbf25aa4a973dd352564a9000af69edca90623e8a16dad9cbc03713131311"
+dependencies = [
+ "bstr",
+ "gix-glob",
+ "gix-path",
+ "gix-quote",
+ "gix-trace",
+ "kstring",
+ "smallvec",
+ "thiserror",
+ "unicode-bom",
+]
+
+[[package]]
+name = "gix-bitmap"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a371db66cbd4e13f0ed9dc4c0fea712d7276805fccc877f77e96374d317e87ae"
+dependencies = [
+ "thiserror",
+]
+
+[[package]]
+name = "gix-chunk"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45c8751169961ba7640b513c3b24af61aa962c967aaf04116734975cd5af0c52"
+dependencies = [
+ "thiserror",
+]
+
+[[package]]
+name = "gix-command"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff2e692b36bbcf09286c70803006ca3fd56551a311de450be317a0ab8ea92e7"
+dependencies = [
+ "bstr",
+ "gix-path",
+ "gix-trace",
+ "shell-words",
+]
+
+[[package]]
+name = "gix-commitgraph"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "133b06f67f565836ec0c473e2116a60fb74f80b6435e21d88013ac0e3c60fc78"
+dependencies = [
+ "bstr",
+ "gix-chunk",
+ "gix-features",
+ "gix-hash",
+ "memmap2",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-config"
+version = "0.40.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78e797487e6ca3552491de1131b4f72202f282fb33f198b1c34406d765b42bb0"
+dependencies = [
+ "bstr",
+ "gix-config-value",
+ "gix-features",
+ "gix-glob",
+ "gix-path",
+ "gix-ref",
+ "gix-sec",
+ "memchr",
+ "once_cell",
+ "smallvec",
+ "thiserror",
+ "unicode-bom",
+ "winnow 0.6.18",
+]
+
+[[package]]
+name = "gix-config-value"
+version = "0.14.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03f76169faa0dec598eac60f83d7fcdd739ec16596eca8fb144c88973dbe6f8c"
+dependencies = [
+ "bitflags 2.6.0",
+ "bstr",
+ "gix-path",
+ "libc",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-date"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35c84b7af01e68daf7a6bb8bb909c1ff5edb3ce4326f1f43063a5a96d3c3c8a5"
+dependencies = [
+ "bstr",
+ "itoa",
+ "jiff",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-diff"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92c9afd80fff00f8b38b1c1928442feb4cd6d2232a6ed806b6b193151a3d336c"
+dependencies = [
+ "bstr",
+ "gix-command",
+ "gix-filter",
+ "gix-fs",
+ "gix-hash",
+ "gix-object",
+ "gix-path",
+ "gix-tempfile",
+ "gix-trace",
+ "gix-worktree",
+ "imara-diff",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-discover"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0577366b9567376bc26e815fd74451ebd0e6218814e242f8e5b7072c58d956d2"
+dependencies = [
+ "bstr",
+ "dunce",
+ "gix-fs",
+ "gix-hash",
+ "gix-path",
+ "gix-ref",
+ "gix-sec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-features"
+version = "0.38.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac7045ac9fe5f9c727f38799d002a7ed3583cd777e3322a7c4b43e3cf437dc69"
+dependencies = [
+ "crc32fast",
+ "crossbeam-channel",
+ "flate2",
+ "gix-hash",
+ "gix-trace",
+ "gix-utils",
+ "libc",
+ "once_cell",
+ "parking_lot",
+ "prodash",
+ "sha1_smol",
+ "thiserror",
+ "walkdir",
+]
+
+[[package]]
+name = "gix-filter"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4121790ae140066e5b953becc72e7496278138d19239be2e63b5067b0843119e"
+dependencies = [
+ "bstr",
+ "encoding_rs",
+ "gix-attributes",
+ "gix-command",
+ "gix-hash",
+ "gix-object",
+ "gix-packetline-blocking",
+ "gix-path",
+ "gix-quote",
+ "gix-trace",
+ "gix-utils",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-fs"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575"
+dependencies = [
+ "fastrand",
+ "gix-features",
+ "gix-utils",
+]
+
+[[package]]
+name = "gix-glob"
+version = "0.16.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74908b4bbc0a0a40852737e5d7889f676f081e340d5451a16e5b4c50d592f111"
+dependencies = [
+ "bitflags 2.6.0",
+ "bstr",
+ "gix-features",
+ "gix-path",
+]
+
+[[package]]
+name = "gix-hash"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e"
+dependencies = [
+ "faster-hex",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-hashtable"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ddf80e16f3c19ac06ce415a38b8591993d3f73aede049cb561becb5b3a8e242"
+dependencies = [
+ "gix-hash",
+ "hashbrown 0.14.5",
+ "parking_lot",
+]
+
+[[package]]
+name = "gix-ignore"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e447cd96598460f5906a0f6c75e950a39f98c2705fc755ad2f2020c9e937fab7"
+dependencies = [
+ "bstr",
+ "gix-glob",
+ "gix-path",
+ "gix-trace",
+ "unicode-bom",
+]
+
+[[package]]
+name = "gix-index"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cd4203244444017682176e65fd0180be9298e58ed90bd4a8489a357795ed22d"
+dependencies = [
+ "bitflags 2.6.0",
+ "bstr",
+ "filetime",
+ "fnv",
+ "gix-bitmap",
+ "gix-features",
+ "gix-fs",
+ "gix-hash",
+ "gix-lock",
+ "gix-object",
+ "gix-traverse",
+ "gix-utils",
+ "gix-validate",
+ "hashbrown 0.14.5",
+ "itoa",
+ "libc",
+ "memmap2",
+ "rustix",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-lock"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bc7fe297f1f4614774989c00ec8b1add59571dc9b024b4c00acb7dedd4e19d"
+dependencies = [
+ "gix-tempfile",
+ "gix-utils",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-object"
+version = "0.44.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f5b801834f1de7640731820c2df6ba88d95480dc4ab166a5882f8ff12b88efa"
+dependencies = [
+ "bstr",
+ "gix-actor",
+ "gix-date",
+ "gix-features",
+ "gix-hash",
+ "gix-utils",
+ "gix-validate",
+ "itoa",
+ "smallvec",
+ "thiserror",
+ "winnow 0.6.18",
+]
+
+[[package]]
+name = "gix-odb"
+version = "0.63.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3158068701c17df54f0ab2adda527f5a6aca38fd5fd80ceb7e3c0a2717ec747"
+dependencies = [
+ "arc-swap",
+ "gix-date",
+ "gix-features",
+ "gix-fs",
+ "gix-hash",
+ "gix-object",
+ "gix-pack",
+ "gix-path",
+ "gix-quote",
+ "parking_lot",
+ "tempfile",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-pack"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3223aa342eee21e1e0e403cad8ae9caf9edca55ef84c347738d10681676fd954"
+dependencies = [
+ "clru",
+ "gix-chunk",
+ "gix-features",
+ "gix-hash",
+ "gix-hashtable",
+ "gix-object",
+ "gix-path",
+ "memmap2",
+ "smallvec",
+ "thiserror",
+ "uluru",
+]
+
+[[package]]
+name = "gix-packetline-blocking"
+version = "0.17.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9802304baa798dd6f5ff8008a2b6516d54b74a69ca2d3a2b9e2d6c3b5556b40"
+dependencies = [
+ "bstr",
+ "faster-hex",
+ "gix-trace",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-path"
+version = "0.10.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebfc4febd088abdcbc9f1246896e57e37b7a34f6909840045a1767c6dafac7af"
+dependencies = [
+ "bstr",
+ "gix-trace",
+ "home",
+ "once_cell",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-pathspec"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d23bf239532b4414d0e63b8ab3a65481881f7237ed9647bb10c1e3cc54c5ceb"
+dependencies = [
+ "bitflags 2.6.0",
+ "bstr",
+ "gix-attributes",
+ "gix-config-value",
+ "gix-glob",
+ "gix-path",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-quote"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbff4f9b9ea3fa7a25a70ee62f545143abef624ac6aa5884344e70c8b0a1d9ff"
+dependencies = [
+ "bstr",
+ "gix-utils",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-ref"
+version = "0.47.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae0d8406ebf9aaa91f55a57f053c5a1ad1a39f60fdf0303142b7be7ea44311e5"
+dependencies = [
+ "gix-actor",
+ "gix-features",
+ "gix-fs",
+ "gix-hash",
+ "gix-lock",
+ "gix-object",
+ "gix-path",
+ "gix-tempfile",
+ "gix-utils",
+ "gix-validate",
+ "memmap2",
+ "thiserror",
+ "winnow 0.6.18",
+]
+
+[[package]]
+name = "gix-refspec"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebb005f82341ba67615ffdd9f7742c87787544441c88090878393d0682869ca6"
+dependencies = [
+ "bstr",
+ "gix-hash",
+ "gix-revision",
+ "gix-validate",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-revision"
+version = "0.29.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba4621b219ac0cdb9256883030c3d56a6c64a6deaa829a92da73b9a576825e1e"
+dependencies = [
+ "bstr",
+ "gix-date",
+ "gix-hash",
+ "gix-object",
+ "gix-revwalk",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-revwalk"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b41e72544b93084ee682ef3d5b31b1ba4d8fa27a017482900e5e044d5b1b3984"
+dependencies = [
+ "gix-commitgraph",
+ "gix-date",
+ "gix-hash",
+ "gix-hashtable",
+ "gix-object",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-sec"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fe4d52f30a737bbece5276fab5d3a8b276dc2650df963e293d0673be34e7a5f"
+dependencies = [
+ "bitflags 2.6.0",
+ "gix-path",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "gix-submodule"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "529d0af78cc2f372b3218f15eb1e3d1635a21c8937c12e2dd0b6fc80c2ca874b"
+dependencies = [
+ "bstr",
+ "gix-config",
+ "gix-path",
+ "gix-pathspec",
+ "gix-refspec",
+ "gix-url",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-tempfile"
+version = "14.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "046b4927969fa816a150a0cda2e62c80016fe11fb3c3184e4dddf4e542f108aa"
+dependencies = [
+ "dashmap",
+ "gix-fs",
+ "libc",
+ "once_cell",
+ "parking_lot",
+ "tempfile",
+]
+
+[[package]]
+name = "gix-trace"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6cae0e8661c3ff92688ce1c8b8058b3efb312aba9492bbe93661a21705ab431b"
+
+[[package]]
+name = "gix-traverse"
+version = "0.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "030da39af94e4df35472e9318228f36530989327906f38e27807df305fccb780"
+dependencies = [
+ "bitflags 2.6.0",
+ "gix-commitgraph",
+ "gix-date",
+ "gix-hash",
+ "gix-hashtable",
+ "gix-object",
+ "gix-revwalk",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-url"
+version = "0.27.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd280c5e84fb22e128ed2a053a0daeacb6379469be6a85e3d518a0636e160c89"
+dependencies = [
+ "bstr",
+ "gix-features",
+ "gix-path",
+ "home",
+ "thiserror",
+ "url",
+]
+
+[[package]]
+name = "gix-utils"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35192df7fd0fa112263bad8021e2df7167df4cc2a6e6d15892e1e55621d3d4dc"
+dependencies = [
+ "fastrand",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "gix-validate"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81f2badbb64e57b404593ee26b752c26991910fd0d81fe6f9a71c1a8309b6c86"
+dependencies = [
+ "bstr",
+ "thiserror",
+]
+
+[[package]]
+name = "gix-worktree"
+version = "0.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c312ad76a3f2ba8e865b360d5cb3aa04660971d16dec6dd0ce717938d903149a"
+dependencies = [
+ "bstr",
+ "gix-attributes",
+ "gix-features",
+ "gix-fs",
+ "gix-glob",
+ "gix-hash",
+ "gix-ignore",
+ "gix-index",
+ "gix-object",
+ "gix-path",
+ "gix-validate",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "globset"
+version = "0.4.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19"
+dependencies = [
+ "aho-corasick",
+ "bstr",
+ "log",
+ "regex-automata 0.4.8",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "half"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
+dependencies = [
+ "cfg-if",
+ "crunchy",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hermit-abi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+
+[[package]]
+name = "hermit-abi"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
+
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "idna"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "ignore"
+version = "0.4.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
+dependencies = [
+ "crossbeam-deque",
+ "globset",
+ "log",
+ "memchr",
+ "regex-automata 0.4.8",
+ "same-file",
+ "walkdir",
+ "winapi-util",
+]
+
+[[package]]
+name = "imara-diff"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc9da1a252bd44cd341657203722352efc9bc0c847d06ea6d2dc1cd1135e0a01"
+dependencies = [
+ "ahash",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.1",
+]
+
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
+[[package]]
+name = "insta"
+version = "1.41.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8"
+dependencies = [
+ "console",
+ "lazy_static",
+ "linked-hash-map",
+ "regex",
+ "similar",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "is-terminal"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
+dependencies = [
+ "hermit-abi 0.4.0",
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "jiff"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "437651126da47900d4d70255ab15f5c69510ca4e0d88c9f01b5b8d41a45c3a9b"
+dependencies = [
+ "jiff-tzdb-platform",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "jiff-tzdb"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05fac328b3df1c0f18a3c2ab6cb7e06e4e549f366017d796e3e66b6d6889abe6"
+
+[[package]]
+name = "jiff-tzdb-platform"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8da387d5feaf355954c2c122c194d6df9c57d865125a67984bb453db5336940"
+dependencies = [
+ "jiff-tzdb",
+]
+
+[[package]]
+name = "jj-cli"
+version = "0.23.0"
+dependencies = [
+ "anyhow",
+ "assert_cmd",
+ "assert_matches",
+ "async-trait",
+ "bstr",
+ "chrono",
+ "clap",
+ "clap-markdown",
+ "clap_complete",
+ "clap_complete_nushell",
+ "clap_mangen",
+ "config",
+ "criterion",
+ "crossterm",
+ "dirs",
+ "dunce",
+ "esl01-renderdag",
+ "futures 0.3.31",
+ "git2",
+ "gix",
+ "indexmap",
+ "indoc",
+ "insta",
+ "itertools 0.13.0",
+ "jj-cli",
+ "jj-lib",
+ "libc",
+ "maplit",
+ "minus",
+ "once_cell",
+ "pest",
+ "pest_derive",
+ "pollster",
+ "rayon",
+ "regex",
+ "rpassword",
+ "scm-record",
+ "serde",
+ "slab",
+ "strsim",
+ "tempfile",
+ "test-case",
+ "testutils",
+ "textwrap",
+ "thiserror",
+ "timeago",
+ "toml_edit",
+ "tracing",
+ "tracing-chrome",
+ "tracing-subscriber",
+ "unicode-width",
+]
+
+[[package]]
+name = "jj-lib"
+version = "0.23.0"
+dependencies = [
+ "assert_matches",
+ "async-trait",
+ "backoff",
+ "blake2",
+ "bstr",
+ "chrono",
+ "chrono-english",
+ "clru",
+ "config",
+ "criterion",
+ "digest",
+ "either",
+ "esl01-renderdag",
+ "futures 0.3.31",
+ "git2",
+ "gix",
+ "gix-filter",
+ "glob",
+ "hashbrown 0.15.1",
+ "hex",
+ "ignore",
+ "indexmap",
+ "indoc",
+ "insta",
+ "itertools 0.13.0",
+ "jj-lib-proc-macros",
+ "maplit",
+ "num_cpus",
+ "once_cell",
+ "pest",
+ "pest_derive",
+ "pollster",
+ "pretty_assertions",
+ "prost",
+ "rand",
+ "rand_chacha",
+ "rayon",
+ "ref-cast",
+ "regex",
+ "rustix",
+ "same-file",
+ "serde",
+ "serde_json",
+ "smallvec",
+ "strsim",
+ "tempfile",
+ "test-case",
+ "testutils",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "version_check",
+ "watchman_client",
+ "whoami",
+ "winreg",
+ "zstd",
+]
+
+[[package]]
+name = "jj-lib-proc-macros"
+version = "0.23.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "kstring"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "558bf9508a558512042d3095138b1f7b8fe90c5467d94f9f1da28b3731c5dbd1"
+dependencies = [
+ "static_assertions",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.161"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+
+[[package]]
+name = "libgit2-sys"
+version = "0.17.0+1.8.1"
+source = "git+https://github.com/bnjmnt4n/git2-rs.git?rev=60e29ff0d#60e29ff0d84cdffd9f366455d32606e582a4c378"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+]
+
+[[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.6.0",
+ "libc",
+ "redox_syscall",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "lru"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
+dependencies = [
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+
+[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata 0.1.10",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memmap2"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "minus"
+version = "5.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "093bd0520d2a37943566a73750e6d44094dac75d66a978d1f0d97ffc78686832"
+dependencies = [
+ "crossbeam-channel",
+ "crossterm",
+ "once_cell",
+ "parking_lot",
+ "regex",
+ "textwrap",
+ "thiserror",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+ "wasi",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "multimap"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+dependencies = [
+ "hermit-abi 0.3.9",
+ "libc",
+]
+
+[[package]]
+name = "object"
+version = "0.36.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+dependencies = [
+ "parking_lot_core",
+]
+
+[[package]]
+name = "oorandom"
+version = "11.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-src"
+version = "300.3.2+3.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
+dependencies = [
+ "cc",
+ "libc",
+ "openssl-src",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "overload"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pathdiff"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pest"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "plotters"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3"
+dependencies = [
+ "num-traits",
+ "plotters-backend",
+ "plotters-svg",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "plotters-backend"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7"
+
+[[package]]
+name = "plotters-svg"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705"
+dependencies = [
+ "plotters-backend",
+]
+
+[[package]]
+name = "pollster"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "predicates"
+version = "3.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
+dependencies = [
+ "anstyle",
+ "difflib",
+ "predicates-core",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
+dependencies = [
+ "predicates-core",
+ "termtree",
+]
+
+[[package]]
+name = "pretty_assertions"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
+dependencies = [
+ "diff",
+ "yansi",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "prodash"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
+
+[[package]]
+name = "prost"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29"
+dependencies = [
+ "bytes",
+ "prost-derive",
+]
+
+[[package]]
+name = "prost-build"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
+dependencies = [
+ "bytes",
+ "heck",
+ "itertools 0.12.1",
+ "log",
+ "multimap",
+ "once_cell",
+ "petgraph",
+ "prettyplease",
+ "prost",
+ "prost-types",
+ "regex",
+ "syn",
+ "tempfile",
+]
+
+[[package]]
+name = "prost-derive"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
+dependencies = [
+ "anyhow",
+ "itertools 0.12.1",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "prost-types"
+version = "0.12.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0"
+dependencies = [
+ "prost",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "ratatui"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3"
+dependencies = [
+ "bitflags 2.6.0",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "itertools 0.13.0",
+ "lru",
+ "paste",
+ "stability",
+ "strum",
+ "strum_macros",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.4.8",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax 0.6.29",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax 0.8.5",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
+[[package]]
+name = "roff"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
+
+[[package]]
+name = "rpassword"
+version = "7.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f"
+dependencies = [
+ "libc",
+ "rtoolbox",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rtoolbox"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+
+[[package]]
+name = "rustix"
+version = "0.38.39"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee"
+dependencies = [
+ "bitflags 2.6.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scanlex"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "088c5d71572124929ea7549a8ce98e1a6fd33d0a38367b09027b382e67c033db"
+
+[[package]]
+name = "scm-record"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d344fd2a7dd1580458c344f977c64ce7b1b1ad1d4f959ab6d2ca2cbab44de69"
+dependencies = [
+ "cassowary",
+ "crossterm",
+ "num-traits",
+ "ratatui",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "tracing",
+ "unicode-width",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bser"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56b4bcc15e42e5b5ae16c6f75582bef80d36c6ffe2c03b1b5317754b38f8717"
+dependencies = [
+ "anyhow",
+ "byteorder",
+ "bytes",
+ "serde",
+ "serde_bytes",
+ "thiserror",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.210"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.132"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "sha1_smol"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shell-words"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio 0.8.11",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "similar"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "smawk"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
+
+[[package]]
+name = "socket2"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "stability"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "2.0.87"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
+dependencies = [
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "termtree"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+
+[[package]]
+name = "test-case"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8"
+dependencies = [
+ "test-case-macros",
+]
+
+[[package]]
+name = "test-case-core"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f"
+dependencies = [
+ "cfg-if",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "test-case-macros"
+version = "3.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "test-case-core",
+]
+
+[[package]]
+name = "testutils"
+version = "0.23.0"
+dependencies = [
+ "async-trait",
+ "config",
+ "futures 0.3.31",
+ "git2",
+ "hex",
+ "itertools 0.13.0",
+ "jj-lib",
+ "pollster",
+ "rand",
+ "tempfile",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
+dependencies = [
+ "smawk",
+ "unicode-linebreak",
+ "unicode-width",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+]
+
+[[package]]
+name = "timeago"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1710e589de0a76aaf295cd47a6699f6405737dbfd3cf2b75c92d000b548d0e6"
+
+[[package]]
+name = "tinytemplate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.41.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio 1.0.2",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "log",
+ "pin-project-lite",
+ "slab",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-chrome"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf0a738ed5d6450a9fb96e86a23ad808de2b727fd1394585da5cdd6788ffe724"
+dependencies = [
+ "serde_json",
+ "tracing-core",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+
+[[package]]
+name = "uluru"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c8a2469e56e6e5095c82ccd3afb98dad95f7af7929aab6d8ba8d6e0f73657da"
+dependencies = [
+ "arrayvec",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+
+[[package]]
+name = "unicode-bom"
+version = "2.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eec5d1121208364f6793f7d2e222bf75a915c19557537745b195b253dd64217"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "unicode-truncate"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
+dependencies = [
+ "itertools 0.13.0",
+ "unicode-segmentation",
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "url"
+version = "2.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "watchman_client"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88bc4c9bb443a7aae10d4fa7807bffc397805315e2305288c90c80e2f66cfb52"
+dependencies = [
+ "anyhow",
+ "bytes",
+ "futures 0.3.31",
+ "maplit",
+ "serde",
+ "serde_bser",
+ "thiserror",
+ "tokio",
+ "tokio-util",
+ "winapi",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "whoami"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
+dependencies = [
+ "redox_syscall",
+ "wasite",
+ "web-sys",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winreg"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5"
+dependencies = [
+ "cfg-if",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "yansi"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zstd"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "6.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581"
+dependencies = [
+ "libc",
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.13+zstd.1.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/pkgs/jujutsu-openssh/default.nix b/pkgs/jujutsu-openssh/default.nix
new file mode 100644
index 0000000..ff65c83
--- /dev/null
+++ b/pkgs/jujutsu-openssh/default.nix
@@ -0,0 +1,89 @@
+{
+  lib,
+  fetchFromGitHub,
+  rustPlatform,
+  pkg-config,
+  openssl,
+  gzip,
+  libgit2,
+  openssh,
+  zstd,
+  installShellFiles,
+  nix-update-script,
+  testers,
+  jujutsu-openssh,
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "jujutsu-openssh";
+  version = "0.23.0+pr3191.openssh";
+
+  src = fetchFromGitHub {
+    owner = "dln";
+    repo = "jj";
+    rev = "aa61f294708502d4faf120720252b4aa76157f2d"; # https://github.com/dln/jj/tree/openssh
+    hash = "sha256-5U873EtczuQBysXmfhLh0wrZ7rdkszOKHlakROBckWI=";
+  };
+
+  cargoLock.lockFile = ./Cargo.lock;
+  cargoLock.outputHashes = {
+    "git2-0.19.0" = "sha256-fV8dFChGeDhb20bMyqefpAD5/+raQQ2sMdkEtlA1jaE=";
+  };
+
+  cargoBuildFlags = [
+    "--bin"
+    "jj"
+  ]; # don't install the fake editors
+  useNextest = false; # nextest is the upstream integration framework, but is problematic for test skipping
+  ZSTD_SYS_USE_PKG_CONFIG = "1"; # disable vendored zlib
+
+  nativeBuildInputs = [
+    gzip
+    installShellFiles
+    pkg-config
+  ];
+
+  buildInputs = [
+    openssl
+    zstd
+    libgit2
+    openssh
+  ];
+
+  postInstall = ''
+    $out/bin/jj util mangen > ./jj.1
+    installManPage ./jj.1
+
+    installShellCompletion --cmd jj \
+      --bash <($out/bin/jj util completion bash) \
+      --fish <($out/bin/jj util completion fish) \
+      --zsh <($out/bin/jj util completion zsh)
+  '';
+
+  checkFlags = [
+    # signing tests spin up an ssh-agent and do git checkouts
+    "--skip=test_ssh_signing"
+  ];
+
+  passthru = {
+    updateScript = nix-update-script { };
+    tests = {
+      version = testers.testVersion {
+        package = jujutsu-openssh;
+        command = "jj --version";
+      };
+    };
+  };
+
+  meta = with lib; {
+    description = "Git-compatible DVCS that is both simple and powerful";
+    homepage = "https://github.com/martinvonz/jj";
+    changelog = "https://github.com/martinvonz/jj/blob/v${version}/CHANGELOG.md";
+    license = licenses.asl20;
+    maintainers = with maintainers; [
+      _0x4A6F
+      thoughtpolice
+    ];
+    mainProgram = "jj";
+  };
+}
diff --git a/pkgs/lazyjj/default.nix b/pkgs/lazyjj/default.nix
new file mode 100644
index 0000000..c253e67
--- /dev/null
+++ b/pkgs/lazyjj/default.nix
@@ -0,0 +1,30 @@
+{
+  stdenvNoCC,
+  fetchzip,
+}:
+let
+  version = "0.3.1";
+in
+stdenvNoCC.mkDerivation {
+  name = "lazyjj";
+  inherit version;
+
+  src = fetchzip {
+    url = "https://github.com/Cretezy/lazyjj/releases/download/v0.3.1/lazyjj-v0.3.1-x86_64-unknown-linux-musl.tar.gz";
+    hash = "sha256-6R4W6uyq8sns8WLoJxp06xAYaJ0Zn+pZLtwhVIPobmc=";
+  };
+
+  installPhase = ''
+    runHook preInstall
+    mkdir -p $out/bin
+    install -m755 -D $src/lazyjj $out/bin/lazyjj
+    runHook postInstall
+  '';
+
+  meta = {
+    homepage = "https://github.com/Cretezy/lazyjj";
+    description = "TUI for jj";
+    mainProgram = "lazyjj";
+    platforms = [ "x86_64-linux" ];
+  };
+}