Files
dotfiles/docs/superpowers/plans/2026-05-25-hyprlock-replace-gtklock.md
funman300 467be569fd docs: implementation plan for hyprlock migration
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:10:50 -07:00

13 KiB

Replace gtklock with hyprlock Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Swap the lockscreen from gtklock to hyprlock so fingerprint unlock works without typing a character first.

Architecture: Replace one tracked config tree (gtklock/) with another (hyprlock/). Update packages.txt, install.sh, niri/config.kdl, scripts/enable-fingerprint.sh, and docs. The user re-runs install.sh + enable-fingerprint.sh after merge.

Tech Stack: Hyprlang config, niri, bash, PAM.

Spec: docs/superpowers/specs/2026-05-25-hyprlock-replace-gtklock-design.md

Verification model: niri validate for niri changes, bash -n for shell, parse-check for the Hyprlang config (hyprlock --help won't validate config without -c; spec-correctness is via inspection). Functional end-to-end (touch reader → unlock) is interactive — controller verifies after the live install + bootstrap.


File Structure

File Role
hyprlock/hyprlock.conf New — single Hyprlang file, deployed to ~/.config/hypr/hyprlock.conf
packages.txt swap gtklockhyprlock, drop gtklock-userinfo-module if present
install.sh drop gtklock symlinks + the gtklock mkdir entry, add hyprlock symlink
niri/config.kdl swap 3 gtklock invocations (Mod+Shift+E + 2 swayidle)
scripts/enable-fingerprint.sh swap target in TARGETS array
gtklock/config.ini, gtklock/style.css deleted
README.md, ARCHITECTURE.md, CLAUDE.md swap lockscreen references

5 tasks, each atomic.


Task 1: Add hyprlock config + swap install.sh + packages.txt

After this task: hyprlock is in packages.txt, hyprlock/hyprlock.conf exists, install.sh symlinks it into ~/.config/hypr/ (mkdir-ing the dir if needed), and the gtklock symlinks are gone from install.sh. The repo still has gtklock/ files and niri still calls gtklock — Tasks 2-4 finish the swap.

Files:

  • Create: hyprlock/hyprlock.conf

  • Modify: packages.txt

  • Modify: install.sh (lines 19, 43-44)

  • Step 1: Create hyprlock/hyprlock.conf

mkdir -p hyprlock

Write hyprlock/hyprlock.conf with this exact content:

general {
    grace = 0
    hide_cursor = true
}

background {
    monitor =
    path = screenshot
    blur_passes = 3
    blur_size = 8
}

label {
    monitor =
    text = cmd[update:1000] date +"%-I:%M %p"
    font_size = 96
    color = rgba(c5c8c6ff)
    position = 0, 150
    halign = center
    valign = center
}

label {
    monitor =
    text = cmd[update:60000] date +"%A, %B %-d"
    font_size = 24
    color = rgba(969896ff)
    position = 0, 40
    halign = center
    valign = center
}

input-field {
    monitor =
    size = 300, 50
    outline_thickness = 2
    dots_size = 0.25
    dots_spacing = 0.4
    inner_color = rgba(282a2eff)
    outer_color = rgba(81a2beff)
    font_color = rgba(c5c8c6ff)
    fail_color = rgba(cc6666ff)
    check_color = rgba(b5bd68ff)
    placeholder_text = <i>Touch fingerprint or type password</i>
    fail_text = <i>$FAIL</i>
    fade_on_empty = false
    position = 0, -50
    halign = center
    valign = center
}
  • Step 2: Update packages.txt

Currently gtklock is on line 13 (between pamixer and swayidle):

gtklock
swayidle

Replace gtklock with hyprlock:

hyprlock
swayidle

If gtklock-userinfo-module appears anywhere in the file, also delete that line. Verify with:

grep -E "gtklock" packages.txt

Expected: zero matches after edit.

grep -c "^hyprlock$" packages.txt

Expected: 1.

  • Step 3: Update install.sh — remove gtklock symlinks and entry, add hyprlock symlink

Find lines 43-44:

ln -sf "$(pwd)/gtklock/config.ini" ~/.config/gtklock/config
ln -sf "$(pwd)/gtklock/style.css" ~/.config/gtklock/style.css

Replace both lines with:

mkdir -p ~/.config/hypr
ln -sf "$(pwd)/hyprlock/hyprlock.conf" ~/.config/hypr/hyprlock.conf

Also find line 19 (the brace-expansion mkdir):

mkdir -p ~/.config/{niri,waybar,wofi,mako,alacritty,gtk-3.0,gtk-4.0,gtklock,fish} ~/.config/environment.d ~/.config/xdg-desktop-portal

Remove gtklock, from the brace list (no need to mkdir gtklock anymore):

mkdir -p ~/.config/{niri,waybar,wofi,mako,alacritty,gtk-3.0,gtk-4.0,fish} ~/.config/environment.d ~/.config/xdg-desktop-portal
  • Step 4: Bash-syntax-check install.sh
bash -n install.sh && echo "syntax ok"

Expected: syntax ok, exit 0.

  • Step 5: Confirm changes landed
grep -nE "gtklock|hyprlock" install.sh

Expected: 2 hits — both for hyprlock (mkdir -p ~/.config/hypr and the ln -sf ... hyprlock.conf line). No gtklock references remain.

ls hyprlock/hyprlock.conf && wc -l hyprlock/hyprlock.conf

Expected: file exists, ~52 lines.

  • Step 6: Commit
git add hyprlock/hyprlock.conf packages.txt install.sh
git commit -m "hyprlock: add config + swap install.sh away from gtklock"

Task 2: Swap niri keybind + swayidle hooks from gtklock to hyprlock

After this task, niri's lock keybind and swayidle's lock-on-idle/before-sleep hooks all call hyprlock instead of gtklock -d. The repo still has the gtklock/ config files and the old PAM target in enable-fingerprint.sh — Tasks 3-4 finish those.

Files:

  • Modify: niri/config.kdl

  • Step 1: Find the three gtklock invocations

grep -n "gtklock" niri/config.kdl

Expected: 3 matches — one in the swayidle spawn-at-startup line (with two "gtklock" "-d" substrings — counts as the same line, may show twice if grep prints once per line), and one keybind line Mod+Shift+E { spawn "gtklock" "-d"; }.

  • Step 2: Replace the keybind

Find Mod+Shift+E { spawn "gtklock" "-d"; } and replace with:

    Mod+Shift+E { spawn "hyprlock"; }

Indentation: 4 spaces, matching the surrounding binds block entries.

  • Step 3: Replace the swayidle line's two "gtklock" "-d" occurrences

The swayidle spawn-at-startup line looks like:

spawn-at-startup "swayidle" "-w" "timeout" "300" "niri msg action power-off-monitors" "timeout" "600" "gtklock" "-d" "timeout" "1800" "systemctl suspend-then-hibernate" "before-sleep" "gtklock" "-d"

Replace both "gtklock" "-d" substrings with "hyprlock". The full line becomes:

spawn-at-startup "swayidle" "-w" "timeout" "300" "niri msg action power-off-monitors" "timeout" "600" "hyprlock" "timeout" "1800" "systemctl suspend-then-hibernate" "before-sleep" "hyprlock"

Note: each "gtklock" "-d" (two quoted strings, two niri spawn args) becomes a single "hyprlock" (one quoted string).

  • Step 4: Validate niri config
niri validate 2>&1 | tail -2

Expected: a final INFO niri: config is valid. Exit 0.

  • Step 5: Confirm gtklock is gone, hyprlock present
grep -c "gtklock" niri/config.kdl
grep -c "hyprlock" niri/config.kdl

Expected: 0 for gtklock, 3 for hyprlock (one keybind + two swayidle action positions).

  • Step 6: Commit
git add niri/config.kdl
git commit -m "niri: switch lock + idle hooks to hyprlock"

Task 3: Update scripts/enable-fingerprint.sh PAM target

After this task, re-running the script targets /etc/pam.d/hyprlock instead of /etc/pam.d/gtklock. The existing line in /etc/pam.d/gtklock is left in place on the live system (harmless dead config — see Out of Scope in the spec).

Files:

  • Modify: scripts/enable-fingerprint.sh (one line in the TARGETS array)

  • Step 1: Find the TARGETS line

grep -n "TARGETS" scripts/enable-fingerprint.sh

Expected: one line like:

TARGETS=(/etc/pam.d/sudo /etc/pam.d/gtklock)
  • Step 2: Replace gtklock with hyprlock

Change the line to:

TARGETS=(/etc/pam.d/sudo /etc/pam.d/hyprlock)
  • Step 3: Syntax-check
bash -n scripts/enable-fingerprint.sh && echo "syntax ok"

Expected: syntax ok, exit 0.

  • Step 4: Confirm the swap
grep -n "gtklock\|hyprlock" scripts/enable-fingerprint.sh

Expected: one match — the new hyprlock line. Zero gtklock references.

  • Step 5: Commit
git add scripts/enable-fingerprint.sh
git commit -m "scripts: enable-fingerprint targets hyprlock PAM file"

Task 4: Delete the tracked gtklock/ directory

After this task, the repo no longer carries gtklock/config.ini or gtklock/style.css. The system's /etc/pam.d/gtklock (with the harmless dead pam_fprintd line) is untouched. The user's ~/.config/gtklock/ symlinks become broken but harmless since gtklock is no longer launched.

Files:

  • Delete: gtklock/config.ini

  • Delete: gtklock/style.css

  • Step 1: Remove the tracked files

git rm gtklock/config.ini gtklock/style.css

Expected output:

rm 'gtklock/config.ini'
rm 'gtklock/style.css'

The empty gtklock/ directory may remain — git ignores empty directories. If it bothers you cosmetically, rmdir gtklock to clean up.

  • Step 2: Confirm no references remain in the repo (outside docs)
grep -rn "gtklock" --exclude-dir=.git --exclude-dir=docs --exclude-dir=.claude /home/alex/Documents/dotfiles

Expected: only matches in README.md, ARCHITECTURE.md, CLAUDE.md (those get updated in Task 5). No matches in install.sh, niri/, scripts/, packages.txt, or the deleted gtklock/ directory.

  • Step 3: Commit
git commit -m "gtklock: delete tracked config (replaced by hyprlock)"

(git rm already staged the deletions; no further git add needed.)


Task 5: Update README, ARCHITECTURE, CLAUDE.md

After this task, all documentation references hyprlock instead of gtklock.

Files:

  • Modify: README.md

  • Modify: ARCHITECTURE.md

  • Modify: CLAUDE.md

  • Step 1: Find every gtklock reference in the three docs

grep -n "gtklock" README.md ARCHITECTURE.md CLAUDE.md

Expected: a small handful of matches. Most are in tooling tables (| Lockscreen | gtklock |) and short narrative mentions.

  • Step 2: README.md — replace each gtklock occurrence with hyprlock

For each line grep returned in README.md, change gtklockhyprlock. Most likely:

  • A tooling table row: | Lockscreen | gtklock || Lockscreen | hyprlock |
  • The Mod+Shift+E mention in the fingerprint setup section, if it referenced gtklock by name (verify against the actual line — it may already be Mod+Shift+E to lock without naming the lockscreen)

For each match, use sed -i 's/gtklock/hyprlock/g' README.md if every occurrence should change verbatim, or hand-edit if context requires more thought (rare for this kind of swap).

Verify after:

grep -n "gtklock" README.md

Expected: zero matches.

grep -c "hyprlock" README.md

Expected: matches the count from Step 1 (1-for-1 replacement).

  • Step 3: ARCHITECTURE.md — same swap
sed -i 's/gtklock/hyprlock/g' ARCHITECTURE.md
grep -n "gtklock" ARCHITECTURE.md

Expected: zero matches.

  • Step 4: CLAUDE.md — same swap
sed -i 's/gtklock/hyprlock/g' CLAUDE.md
grep -n "gtklock" CLAUDE.md

Expected: zero matches.

  • Step 5: Final repo-wide sanity check
grep -rn "gtklock" --exclude-dir=.git --exclude-dir=docs --exclude-dir=.claude /home/alex/Documents/dotfiles

Expected: zero matches anywhere except inside docs/ (the historical spec/plan files for the original gtklock setup) and .claude/ (cached permission entries).

  • Step 6: Commit
git add README.md ARCHITECTURE.md CLAUDE.md
git commit -m "docs: flip lockscreen references to hyprlock"

Final verification (controller, post-merge)

  • Install hyprlock:
bash install.sh
which hyprlock

Expected: /usr/bin/hyprlock.

  • Verify config deployed:
ls -la ~/.config/hypr/hyprlock.conf

Expected: symlink to repo's hyprlock/hyprlock.conf.

  • Re-run PAM bootstrap:
sudo bash scripts/enable-fingerprint.sh

Expected output mentions /etc/pam.d/hyprlock got the new line; /etc/pam.d/sudo "already present — skipping".

  • Verify PAM line is in hyprlock:
grep pam_fprintd /etc/pam.d/hyprlock

Expected: one match.

  • Functional tests:
  1. Mod+Shift+E — locks the screen with clock + date + input field.
  2. Touch the fingerprint reader (without typing anything) — unlocks immediately.
  3. Re-lock; type the password instead — also unlocks (fallback).
  4. Wait 10 min idle — swayidle triggers hyprlock automatically.