Skip to content

GottZ/dotfiles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GottZ Dotfiles

Configuration files, helper scripts and system settings for an Arch Linux workstation. The repo lives in /opt/dotfiles and is managed as root — most files are meant to be symlinked into /etc, /usr/local/bin, /usr/share or $HOME.


Quick start

sudo git clone https://github.com/gottz/dotfiles.git /opt/dotfiles

# symlink what you need, e.g.
ln -s /opt/dotfiles/etc/gitconfig              /etc/gitconfig
ln -s /opt/dotfiles/etc/DIR_COLORS             /etc/DIR_COLORS
ln -s /opt/dotfiles/etc/zsh/zshrc.local        /etc/zsh/zshrc.local
ln -sf /opt/dotfiles/etc/profile.d/*           /etc/profile.d/
ln -sf /opt/dotfiles/usr/local/bin/*           /usr/local/bin/
ln -sf /opt/dotfiles/home/.config/tmux         ~/.config/tmux
ln -sf /opt/dotfiles/home/.config/ghostty      ~/.config/ghostty
ln -sf /opt/dotfiles/home/.config/wezterm      ~/.config/wezterm
ln -sf /opt/dotfiles/home/.ssh/allowed_signers ~/.ssh/allowed_signers

Repository layout

etc/ — system configuration

Path Purpose
gitconfig Global git identity, SSH-based commit/tag signing, defaultBranch = root, rebase-on-pull, fetch.prune, zdiff3 conflict style, autoStash, histogram diff algorithm.
DIR_COLORS Rich dircolors database for ls --color (based on default + custom extensions).
zsh/zshrc.local Zsh config on top of grml-zsh-config — see Zsh section below.
ssh/sshd_config.d/99-gottz.conf Hardened sshd: 10 s login grace, 1 auth attempt, key-only (no passwords).
sudoers.d/00_timeout Sets passwd_timeout=0 — sudo never caches credentials.
docker/__hetzner.daemon.json Docker daemon template for Hetzner nodes: IPv6, ip6tables, large address pools (172.32–192.0.0/12).
pacman.d/hooks/remove_old_cache.hook Pacman hook: runs paccache -rvk1 after every transaction to keep only the last cached version.
modprobe.d/sound-powersave.conf Disables power-save for snd_hda_intel and snd_usb_audio.
modprobe.d/usb-power.conf Disables USB autosuspend, sets mousepoll=0 for lowest latency.
systemd/system/kanata.service Systemd unit that starts kanata with the pocket3.kbd layout.
systemd/system/[email protected] Template unit — systemctl enable kanata@caps loads caps.kbd, etc.
kanata/caps.kbd CapsLock → tap Esc / hold Fn-layer. Fn-layer provides media keys, mouse emulation (QWER/ASDF), browser back/forward. Targets Wooting, Fujitsu, AT, Cherry keyboards.
kanata/cleware.kbd Cleware USB foot switch → mic mute (both keys).
kanata/pocket3.kbd GPD Pocket 3 remap: CapsLock → tap Esc / hold RCtrl, Esc → tap CapsLock / hold RAlt, RShift → < (102nd key).

etc/profile.d/ — shell init scripts

Script What it does
00-local-bin.sh Adds ~/.local/bin, ~/go/bin, /opt/dotfiles/.bin to $PATH; sources ~/.cargo/env if present.
01-dircolors.sh Evaluates dircolors -b via the custom /usr/local/bin/dircolors wrapper.
01-editor.sh export EDITOR=nvim
dps.sh Defines dps / dpsa — formatted docker ps with alternating bold rows and multi-line port wrapping.
ipinfo.sh ipinfo <ip> — queries ipinfo.io Lite API (token from ~/.secrets/ipinfo).

home/ — user configuration

Terminals

Both Ghostty and WezTerm share the Kanagawa colour scheme (background #181616, foreground #c5c9c5).

Path Details
.config/ghostty/config Font: Pragmasevka Nerd Font. Kanagawa palette. Unbinds Alt+1–9 (conflict with tmux over SSH).
.config/wezterm/wezterm.lua Font: Pragmasevka Nerd Font. Kanagawa colours. Kitty keyboard protocol. Auto-generates SSH domains from ~/.ssh/config (plain + multiplexed). Windows: detects OpenSSH agent pipe, builds launch menu (pwsh, PowerShell, cmd, Git Bash, Elvish, Nu, VS dev prompts). Linux: reads cursor theme/size from gsettings.

tmux

Feature Detail
Plugins TPM (auto-installed), tmux-sensible, tmux-fzf (Ctrl-f).
Keybindings vi copy-mode (v/y), r reload config, g next pane, n/p next/prev window, {/} swap panes.
Status bar Left: session name + attach count. Right: time + date, prefix/green indicator. Window tabs with Nerd Font icons for active, last, marked, zoomed, bell states.
Bell notify alert-bell hook calls tmux-notify to forward bell events via webhook (see tmux-notify).
Settings 50k history, base-index 1, mouse on, 256color + RGB, extended-keys.

Zsh

etc/zsh/zshrc.local — extends grml-zsh-config (pacman -S grml-zsh-config).

Feature Detail
History 1M entries, dedup, ignore-space.
Modern replacements lslsd (all aliases rewritten), catbat --paging=never.
File manager y wrapper for yazi (cd-on-exit).
Fuzzy search fzf --zsh integration (Ctrl-R etc.).
Node Auto-loads nvm from /usr/share/nvm/init-nvm.sh.
tmux shortcut tmxtmux new -As <hostname> (auto-attach named session).
Docker aliases dc, dcu, dcd, dcr, dcdu, dcl, dcdul, dcp, dcpu, dcpul, dce, dcb, dcbn, dcbu, dcbnu — full docker compose workflow. dcpua pulls all non-local images and recreates running compose services.
GitHub Copilot gc, ge (explain), gs (suggest) via gh copilot.
Termux OpenKeychain SSH agent setup when running in Termux.
Misc rootsudo su -.

SSH

File Purpose
.ssh/allowed_signers Maps [email protected] / [email protected] to trusted ed25519 + RSA signing keys (used by gitconfig's gpg.ssh.allowedSignersFile).
.ssh/authorized_keys Public keys authorised for SSH login.

usr/ — helper executables & system overrides

usr/local/bin/

Tool What it does
needsrestart Checks for deleted libs still held open by processes and compares running vs. installed kernel version. Exits non-zero if reboot needed.
dpsql Connects to a Dockerized PostgreSQL: extracts POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB and container IP via docker inspect, then runs psql. Usage: dpsql <container> [psql flags].
loadavg Compiled C binary — prints 1/5/15 min load averages.
colorcheck Awk script — prints a 77-column truecolor gradient to test terminal capabilities.
tmux-notify Forwards tmux bell events to a webhook with full session context. See tmux-notify below.
dircolors Wrapper around /usr/bin/dircolors that prefers ~/.dircolors, falls back to /etc/DIR_COLORS.
lscolors Displays every LS_COLORS entry in its assigned colour with type descriptions. Useful for auditing the dircolors database.

usr/share/wireplumber/wireplumber.conf.d/

File Purpose
no-suspend.conf Disables ALSA suspend for the Hidizs ST2 PRO USB DAC (avoids the ~2 s power-on ramp on resume).

Highlighted features

  • Kanagawa colour scheme — consistent palette across Ghostty, WezTerm and tmux.
  • SSH-signed commits — global git config enforces ed25519 signing for all commits and tags.
  • Keyboard remapping — kanata layouts for CapsLock-as-Esc/Fn, GPD Pocket 3 fixes, and USB foot-switch mic-mute; managed by systemd.
  • Cross-platform WezTerm — one config that works on Arch and Windows (SSH agent, launch menu, shell detection).
  • Docker workflow — 15+ compose aliases, dps pretty-printer, dcpua bulk pull-and-recreate, dpsql container-aware psql.
  • Modern CLI — lsd, bat, yazi, fzf integrated via zshrc; grml-zsh-config as base.
  • Hardened SSH — key-only auth, 1 attempt, 10 s grace period.
  • Low-latency audio/USB — modprobe and WirePlumber tweaks to disable power-save and suspend.
  • tmux-notify — webhook-based bell notifications with full tmux context and debouncing.

tmux-notify

Forwards tmux bell events to a configurable webhook endpoint. Useful for getting notified when a long-running command (e.g. Claude Code) finishes in a detached or background window.

Parameters sent to the webhook

Parameter tmux variable Description
session #{session_name} Session name
window #{window_name} Window name
pane #{pane_index} Pane index
path #{pane_current_path} Working directory of the pane
command #{pane_current_command} Current command running in the pane
active #{window_active} 1 if the bell window is currently focused, 0 otherwise
clients #{session_attached} Number of clients attached to the session (0 = nobody connected)
host #{host} Hostname of the tmux server
window_index #{window_index} Window index number
pane_pid #{pane_pid} PID of the pane process
pane_title #{pane_title} Pane title
window_panes #{window_panes} Number of panes in the window
window_activity #{window_activity} Unix timestamp of last window activity
pane_dead #{pane_dead} 1 if the pane process has exited
session_id #{session_id} Internal tmux session ID
session_windows #{session_windows} Number of windows in the session

All parameters are sent as a JSON POST body with proper types (strings and numbers).

Configuration

In order of precedence:

  1. CLI flags--webhook-url, --debounce
  2. Environment variablesTMUX_NOTIFY_WEBHOOK_URL, TMUX_NOTIFY_DEBOUNCE
  3. Config file~/.config/tmux-notify/config
# ~/.config/tmux-notify/config
WEBHOOK_URL="https://example.com/webhook/your-endpoint"
DEBOUNCE_SECONDS=5

tmux integration

The alert-bell hook in tmux.conf calls tmux-notify whenever a bell fires in a non-active window:

if-shell 'command -v tmux-notify' {
  set-option -g monitor-bell on
  set-hook -g alert-bell 'run-shell -b "tmux-notify --session #{q:session_name} --window #{q:window_name} --pane #{q:pane_index} --path #{q:pane_current_path} --command #{q:pane_current_command} --active #{window_active} --clients #{session_attached} --host #{host} --window-index #{window_index} --pane-pid #{pane_pid} --pane-title #{q:pane_title} --window-panes #{window_panes} --window-activity #{window_activity} --pane-dead #{pane_dead} --session-id #{session_id} --session-windows #{session_windows}"'
}

Example: n8n webhook workflow

A minimal n8n workflow that receives the bell event and sends an SMS — unless the user is connected and looking at the active window:

Webhook (POST) → inactive or disconnected? (active=0 OR clients=0)
  ├─ yes → sms prep → send sms
  └─ no  → [stop, user is watching]
n8n workflow JSON (click to expand)
{
  "name": "tmux sms",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [0, 0],
      "id": "00000000-0000-0000-0000-000000000001",
      "name": "Webhook",
      "webhookId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 3
          },
          "conditions": [
            {
              "id": "00000000-0000-0000-0000-000000000002",
              "leftValue": "={{ $json.body.active }}",
              "rightValue": "=0",
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            },
            {
              "id": "00000000-0000-0000-0000-000000000003",
              "leftValue": "={{ $json.body.clients }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            }
          ],
          "combinator": "or"
        },
        "looseTypeValidation": true,
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [208, 0],
      "id": "00000000-0000-0000-0000-000000000004",
      "name": "inactive or disconnected"
    },
    {
      "parameters": {
        "jsCode": "for (const item of $input.all()) {\n  const {session, window, pane, path} = item.json.body;\n  item.json.sms = `${session}:${pane}/${window} pings in ${path.length > 30 ? '…' : ''}${path.substr(-30)}`;\n}\nreturn $input.all();"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [416, 0],
      "id": "00000000-0000-0000-0000-000000000005",
      "name": "sms prep"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://example.com/api/webhook/your-sms-endpoint",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "message",
              "value": "={{ $json.sms }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [624, 0],
      "id": "00000000-0000-0000-0000-000000000006",
      "name": "send sms"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [[{"node": "inactive or disconnected", "type": "main", "index": 0}]]
    },
    "inactive or disconnected": {
      "main": [
        [{"node": "sms prep", "type": "main", "index": 0}],
        []
      ]
    },
    "sms prep": {
      "main": [[{"node": "send sms", "type": "main", "index": 0}]]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  }
}

The Code node formats the SMS message as session:pane/window pings in …/path (truncated to 30 chars). The If node sends an SMS when the window is inactive (active=0) or nobody is connected (clients=0) — only suppressed when a client is attached and looking at the bell window.


Contributing

Issues, PRs and direct contact welcome.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors