From fc840dd54ead1fe8c84c7d8af3b8269dbf3dfdeb Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 12 Mar 2026 17:34:54 +0200 Subject: [PATCH 01/31] Set core rules for Claude Code behavior --- .claude/CLAUDE.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index d49e6d9..5f4fcab 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,5 +1,14 @@ # Project Instructions +## Core Rules + +- When asked to do ONE thing, do exactly that. Do not proactively migrate dependencies, refactor adjacent code, or expand scope. You may suggest further edits, but wait for confirmation before any scope expansion. +- Prefer the simplest, most localized solution. Changes should target the most-relevant section of code — for example, catch errors in the scope that best handles them rather than injecting data up or down the stack. Take time to think about the best approach rather than quickly jumping to an implementation. + +## Tool Usage Preferences + +For simple factual lookups (package versions, release dates), use targeted, purpose-built commands and local CLI tools first before attempting web searches — e.g. `pip index versions ` for Python, `npm view versions` for Node. Prefer fast local approaches over web research. + ## Container Environment (Podman) This environment runs inside a container with access to a Podman socket shared from the host. There is no `docker` or `podman` CLI available, but you can interact with containers via the Docker-compatible API. From c9c788efe3f1412a585654729a7b753e0637e53f Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Fri, 27 Mar 2026 15:20:31 +0300 Subject: [PATCH 02/31] Correctly update executable links --- .local/share/github-versions/fstar | 2 +- .local/share/github-versions/tlapm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.local/share/github-versions/fstar b/.local/share/github-versions/fstar index 26499f3..b56a055 100755 --- a/.local/share/github-versions/fstar +++ b/.local/share/github-versions/fstar @@ -20,7 +20,7 @@ install_fstar() { rm --force --recursive "${INSTALL_DIR}" && \ mv "${tempdir}"/fstar "$(dirname "${INSTALL_DIR}")" && \ rm --force --recursive "${tempdir}" && \ - ln --symbolic "${INSTALL_DIR}"/bin/fstar.exe "$(systemd-path user-binaries)"/fstar.exe + ln --force --symbolic "${INSTALL_DIR}"/bin/fstar.exe "$(systemd-path user-binaries)"/fstar.exe } github_update "${package}" "${repo}" fstar_resource install_fstar diff --git a/.local/share/github-versions/tlapm b/.local/share/github-versions/tlapm index 2da3899..34e5227 100755 --- a/.local/share/github-versions/tlapm +++ b/.local/share/github-versions/tlapm @@ -19,7 +19,7 @@ install_tlapm() { rm --force --recursive "${INSTALL_DIR}" && \ mv "${tempdir}"/tlapm "$(dirname "${INSTALL_DIR}")" && \ rm --force --recursive "${tempdir}" && \ - ln --symbolic "${INSTALL_DIR}"/bin/tlapm "$(systemd-path user-binaries)"/tlapm + ln --force --symbolic "${INSTALL_DIR}"/bin/tlapm "$(systemd-path user-binaries)"/tlapm } github_update "${package}" "${repo}" tlapm_resource install_tlapm 1.6.0-pre From d5f4376125a418a5834a68cd2ff13d86ce2269c5 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Mon, 6 Apr 2026 21:41:34 +0300 Subject: [PATCH 03/31] Provide installation suggestions for missing utilities --- .config/setup/04-install-deb-packages.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/setup/04-install-deb-packages.sh b/.config/setup/04-install-deb-packages.sh index b742e59..5e7c900 100755 --- a/.config/setup/04-install-deb-packages.sh +++ b/.config/setup/04-install-deb-packages.sh @@ -15,6 +15,7 @@ DEB_PKGS=( borgbackup build-essential catatonit + command-not-found curl default-jdk direnv From bec062d420f751f55228b756f046ca33de198b15 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Mon, 6 Apr 2026 22:44:08 +0300 Subject: [PATCH 04/31] Install a CLI tool for Hetzner Cloud --- .config/setup/04-install-deb-packages.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.config/setup/04-install-deb-packages.sh b/.config/setup/04-install-deb-packages.sh index 5e7c900..6ee1d44 100755 --- a/.config/setup/04-install-deb-packages.sh +++ b/.config/setup/04-install-deb-packages.sh @@ -35,6 +35,7 @@ DEB_PKGS=( graphviz grim guile-3.0 + hcloud-cli htop imagemagick inkscape From 59d1f1d22d5f1f09dfd5c54e2ee6b4ba0b039c1a Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Tue, 7 Apr 2026 20:39:39 +0300 Subject: [PATCH 05/31] DRY the sync backup script --- .local/bin/sync-backup | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.local/bin/sync-backup b/.local/bin/sync-backup index 97edd7a..cf72348 100755 --- a/.local/bin/sync-backup +++ b/.local/bin/sync-backup @@ -6,7 +6,9 @@ IFS=$'\n\t' export BORG_REPO="/media/backup/" if [ "$1" = "service" ]; then - rclone sync "${BORG_REPO}" gdrive-backup:hot-repo/ + extra_args=() else - rclone sync --progress "${BORG_REPO}" gdrive-backup:hot-repo/ + extra_args=(--progress) fi + +rclone sync "${extra_args[@]}" "${BORG_REPO}" gdrive-backup:hot-repo/ From 34bf948ef19cca9be985704b0f8acdab5b4764a3 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Tue, 7 Apr 2026 20:42:20 +0300 Subject: [PATCH 06/31] Update the script to work in strict mode --- .local/bin/sync-backup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.local/bin/sync-backup b/.local/bin/sync-backup index cf72348..4cafc26 100755 --- a/.local/bin/sync-backup +++ b/.local/bin/sync-backup @@ -5,7 +5,7 @@ IFS=$'\n\t' export BORG_REPO="/media/backup/" -if [ "$1" = "service" ]; then +if [ "${1:-}" = "service" ]; then extra_args=() else extra_args=(--progress) From 31106b267dd87af5ddf0f53841aee521d278f48d Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Tue, 7 Apr 2026 20:40:08 +0300 Subject: [PATCH 07/31] Back up the password databases --- .local/bin/sync-backup | 1 + 1 file changed, 1 insertion(+) diff --git a/.local/bin/sync-backup b/.local/bin/sync-backup index 4cafc26..dc3c432 100755 --- a/.local/bin/sync-backup +++ b/.local/bin/sync-backup @@ -12,3 +12,4 @@ else fi rclone sync "${extra_args[@]}" "${BORG_REPO}" gdrive-backup:hot-repo/ +rclone copy "${extra_args[@]}" ~/.keys/ --include '*.kdbx' gdrive-backup:keys/ From 340b20f39e074d2aeb3e08225490acb8306184f3 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Fri, 10 Apr 2026 18:54:53 +0300 Subject: [PATCH 08/31] Sort keybindings --- .config/emacs/init.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.config/emacs/init.el b/.config/emacs/init.el index 3da0d64..c8748eb 100644 --- a/.config/emacs/init.el +++ b/.config/emacs/init.el @@ -30,10 +30,14 @@ (use-package emacs :ensure nil - :bind (("C-z" . nil) - ("C-z i" . find-init-file) + :bind ( + ("C-z" . nil) + ;; keep-sorted start ("C-z f" . ffap) - ("C-z u" . insert-uuid4-at-point)) + ("C-z i" . find-init-file) + ("C-z u" . insert-uuid4-at-point) + ;; keep-sorted end + ) :hook ( ;; keep-sorted start (after-save . executable-make-buffer-file-executable-if-script-p) From 87c66ec157730e912de00c7cbec0d06c51f90c64 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Fri, 10 Apr 2026 18:54:15 +0300 Subject: [PATCH 09/31] Use hardened defaults for SSH connections --- .ssh/config | 1 + .ssh/config.d/90-hardened-security.conf | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 .ssh/config create mode 100644 .ssh/config.d/90-hardened-security.conf diff --git a/.ssh/config b/.ssh/config new file mode 100644 index 0000000..51ec533 --- /dev/null +++ b/.ssh/config @@ -0,0 +1 @@ +Include ~/.ssh/config.d/*.conf diff --git a/.ssh/config.d/90-hardened-security.conf b/.ssh/config.d/90-hardened-security.conf new file mode 100644 index 0000000..47856a4 --- /dev/null +++ b/.ssh/config.d/90-hardened-security.conf @@ -0,0 +1,14 @@ +# SSH client algorithm hardening. +# +# Require PQ-hybrid KEX, AEAD ciphers, Ed25519 keys. +# Applied to all outgoing SSH connections from this machine. +# +# Requires OpenSSH 9.9+ for mlkem768x25519-sha256. + +Host * + KexAlgorithms mlkem768x25519-sha256,sntrup761x25519-sha512@openssh.com + Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com + MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com + HostKeyAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com + PubkeyAcceptedAlgorithms ssh-ed25519,ssh-ed25519-cert-v01@openssh.com + RekeyLimit 1G 1h From 4bd68f4614d90fd150e5e9464aec5aad33fc6a7c Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 11 Apr 2026 00:00:50 +0300 Subject: [PATCH 10/31] Short-circuit installation commands on failure --- .local/share/github-versions/dolt | 4 ++-- .local/share/github-versions/kingfisher | 4 ++-- .local/share/github-versions/minikube | 8 ++++---- .local/share/github-versions/rust-analyzer | 8 ++++---- .local/share/github-versions/uv | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.local/share/github-versions/dolt b/.local/share/github-versions/dolt index 24eab50..9254013 100755 --- a/.local/share/github-versions/dolt +++ b/.local/share/github-versions/dolt @@ -11,8 +11,8 @@ dolt_resource() { } install_dolt() { - tar xz --directory="$(systemd-path user-binaries)" --strip-components=2 dolt-linux-amd64/bin/dolt - chmod 550 "$(systemd-path user-binaries)"/dolt + tar xz --directory="$(systemd-path user-binaries)" --strip-components=2 dolt-linux-amd64/bin/dolt && \ + chmod 550 "$(systemd-path user-binaries)"/dolt } github_update "${package}" "${repo}" dolt_resource install_dolt diff --git a/.local/share/github-versions/kingfisher b/.local/share/github-versions/kingfisher index 10c7f17..f6903dc 100755 --- a/.local/share/github-versions/kingfisher +++ b/.local/share/github-versions/kingfisher @@ -11,8 +11,8 @@ kingfisher_resource() { } install_kingfisher() { - tar xz --directory="$(systemd-path user-binaries)" kingfisher - chmod 550 "$(systemd-path user-binaries)"/kingfisher + tar xz --directory="$(systemd-path user-binaries)" kingfisher && \ + chmod 550 "$(systemd-path user-binaries)"/kingfisher } github_update "${package}" "${repo}" kingfisher_resource install_kingfisher diff --git a/.local/share/github-versions/minikube b/.local/share/github-versions/minikube index 004f74c..8012485 100755 --- a/.local/share/github-versions/minikube +++ b/.local/share/github-versions/minikube @@ -11,10 +11,10 @@ minikube_resource() { } install_minikube() { - tempfile="$(mktemp)" - cat - > "${tempfile}" - chmod 550 "${tempfile}" - mv "${tempfile}" "$(systemd-path user-binaries)"/minikube + tempfile="$(mktemp)" && \ + cat - > "${tempfile}" && \ + chmod 550 "${tempfile}" && \ + mv "${tempfile}" "$(systemd-path user-binaries)"/minikube } github_update "${package}" "${repo}" minikube_resource install_minikube diff --git a/.local/share/github-versions/rust-analyzer b/.local/share/github-versions/rust-analyzer index 1add828..bd41614 100755 --- a/.local/share/github-versions/rust-analyzer +++ b/.local/share/github-versions/rust-analyzer @@ -11,10 +11,10 @@ rust_analyzer_resource() { } install_rust_analyzer() { - tempfile="$(mktemp)" - gunzip --to-stdout - > "${tempfile}" - chmod 550 "${tempfile}" - mv "${tempfile}" "$(systemd-path user-binaries)"/rust-analyzer + tempfile="$(mktemp)" && \ + gunzip --to-stdout - > "${tempfile}" && \ + chmod 550 "${tempfile}" && \ + mv "${tempfile}" "$(systemd-path user-binaries)"/rust-analyzer } github_update "${package}" "${repo}" rust_analyzer_resource install_rust_analyzer diff --git a/.local/share/github-versions/uv b/.local/share/github-versions/uv index b0c0ad9..389c20d 100755 --- a/.local/share/github-versions/uv +++ b/.local/share/github-versions/uv @@ -11,10 +11,10 @@ uv_resource() { } install_uv() { - tempdir="$(mktemp --directory)" - tar xz --directory="${tempdir}" --strip-components=1 && \ - chmod 550 "${tempdir}"/uv "${tempdir}"/uvx && \ - mv --force "${tempdir}"/uv "${tempdir}"/uvx "$(systemd-path user-binaries)" + tempdir="$(mktemp --directory)" && \ + tar xz --directory="${tempdir}" --strip-components=1 && \ + chmod 550 "${tempdir}"/uv "${tempdir}"/uvx && \ + mv --force "${tempdir}"/uv "${tempdir}"/uvx "$(systemd-path user-binaries)" } github_update "${package}" "${repo}" uv_resource install_uv From ce0be360e54cb0ec50d7ededab6b69d8a65cc8a0 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Fri, 10 Apr 2026 23:57:19 +0300 Subject: [PATCH 11/31] Install SimpleX Chat from the GitHub repository --- .local/share/github-versions/simplex-chat | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100755 .local/share/github-versions/simplex-chat diff --git a/.local/share/github-versions/simplex-chat b/.local/share/github-versions/simplex-chat new file mode 100755 index 0000000..82e7977 --- /dev/null +++ b/.local/share/github-versions/simplex-chat @@ -0,0 +1,20 @@ +#! /usr/bin/bash + +set -euo pipefail +IFS=$'\n\t' + +package=simplex-chat +repo=simplex-chat/simplex-chat + +sc_resource() { + echo "simplex-chat-ubuntu-24_04-x86_64" +} + +install_sc() { + tempfile="$(mktemp)" && \ + cat - > "${tempfile}" && \ + chmod 550 "${tempfile}" && \ + mv "${tempfile}" "$(systemd-path user-binaries)"/simplex-chat +} + +github_update "${package}" "${repo}" sc_resource install_sc From 2a383a6c3c7474e8f38e78713089dd55650471e3 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 21:56:06 +0300 Subject: [PATCH 12/31] Restrict service container privileges --- .config/containers/systemd/ollama.container | 2 ++ .config/containers/systemd/plantuml.container | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.config/containers/systemd/ollama.container b/.config/containers/systemd/ollama.container index 98929ac..051de23 100644 --- a/.config/containers/systemd/ollama.container +++ b/.config/containers/systemd/ollama.container @@ -5,9 +5,11 @@ Description=A local LLM server # keep-sorted start AutoUpdate=registry ContainerName=ollama +DropCapability=ALL Environment=OLLAMA_KEEP_ALIVE=10m Image=docker.io/ollama/ollama:latest Network=ollama.network +NoNewPrivileges=true PodmanArgs=--transient-store PublishPort=11434:11434 ReadOnly=true diff --git a/.config/containers/systemd/plantuml.container b/.config/containers/systemd/plantuml.container index aa8057d..0648c34 100644 --- a/.config/containers/systemd/plantuml.container +++ b/.config/containers/systemd/plantuml.container @@ -5,8 +5,10 @@ Description=A local PlantUML server # keep-sorted start AutoUpdate=registry ContainerName=plantuml +DropCapability=ALL Image=docker.io/plantuml/plantuml-server:jetty Network=private +NoNewPrivileges=true PodmanArgs=--transient-store PublishPort=8080:8080 ReadOnly=true From 36a16cc1dd3a5e6b31d530ad14c8717cae907ff9 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 21:58:53 +0300 Subject: [PATCH 13/31] Only expose access ports on the localhost network --- .config/containers/systemd/ollama.container | 2 +- .config/containers/systemd/plantuml.container | 2 +- .config/containers/systemd/transmission.container | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/containers/systemd/ollama.container b/.config/containers/systemd/ollama.container index 051de23..a3a4402 100644 --- a/.config/containers/systemd/ollama.container +++ b/.config/containers/systemd/ollama.container @@ -11,7 +11,7 @@ Image=docker.io/ollama/ollama:latest Network=ollama.network NoNewPrivileges=true PodmanArgs=--transient-store -PublishPort=11434:11434 +PublishPort=127.0.0.1:11434:11434 ReadOnly=true Volume=%h/.local/share/ollama:/root/.ollama:ro,z # keep-sorted end diff --git a/.config/containers/systemd/plantuml.container b/.config/containers/systemd/plantuml.container index 0648c34..7a1b266 100644 --- a/.config/containers/systemd/plantuml.container +++ b/.config/containers/systemd/plantuml.container @@ -10,7 +10,7 @@ Image=docker.io/plantuml/plantuml-server:jetty Network=private NoNewPrivileges=true PodmanArgs=--transient-store -PublishPort=8080:8080 +PublishPort=127.0.0.1:8080:8080 ReadOnly=true # keep-sorted end diff --git a/.config/containers/systemd/transmission.container b/.config/containers/systemd/transmission.container index 6d83357..210cd62 100644 --- a/.config/containers/systemd/transmission.container +++ b/.config/containers/systemd/transmission.container @@ -10,9 +10,9 @@ Environment=PUID=1000 Image=lscr.io/linuxserver/transmission:latest Network=private PodmanArgs=--transient-store +PublishPort=127.0.0.1:9091:9091 PublishPort=51413:51413 PublishPort=51413:51413/udp -PublishPort=9091:9091 ReadOnly=true UserNS=keep-id Volume=%h/.config/transmission:/config:Z From 7be6bccbc9d54e1abad15839427111af7f10e9f4 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 21:59:52 +0300 Subject: [PATCH 14/31] Check for image updates on startup --- .config/containers/systemd/ollama.container | 2 +- .config/containers/systemd/plantuml.container | 2 +- .config/containers/systemd/transmission.container | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/containers/systemd/ollama.container b/.config/containers/systemd/ollama.container index a3a4402..b44121d 100644 --- a/.config/containers/systemd/ollama.container +++ b/.config/containers/systemd/ollama.container @@ -10,7 +10,7 @@ Environment=OLLAMA_KEEP_ALIVE=10m Image=docker.io/ollama/ollama:latest Network=ollama.network NoNewPrivileges=true -PodmanArgs=--transient-store +PodmanArgs=--pull=newer --transient-store PublishPort=127.0.0.1:11434:11434 ReadOnly=true Volume=%h/.local/share/ollama:/root/.ollama:ro,z diff --git a/.config/containers/systemd/plantuml.container b/.config/containers/systemd/plantuml.container index 7a1b266..47e0f49 100644 --- a/.config/containers/systemd/plantuml.container +++ b/.config/containers/systemd/plantuml.container @@ -9,7 +9,7 @@ DropCapability=ALL Image=docker.io/plantuml/plantuml-server:jetty Network=private NoNewPrivileges=true -PodmanArgs=--transient-store +PodmanArgs=--pull=newer --transient-store PublishPort=127.0.0.1:8080:8080 ReadOnly=true # keep-sorted end diff --git a/.config/containers/systemd/transmission.container b/.config/containers/systemd/transmission.container index 210cd62..1f2ec07 100644 --- a/.config/containers/systemd/transmission.container +++ b/.config/containers/systemd/transmission.container @@ -9,7 +9,7 @@ Environment=PGID=1000 Environment=PUID=1000 Image=lscr.io/linuxserver/transmission:latest Network=private -PodmanArgs=--transient-store +PodmanArgs=--pull=newer --transient-store PublishPort=127.0.0.1:9091:9091 PublishPort=51413:51413 PublishPort=51413:51413/udp From bebbefcda71aaed117b302e3d7e6213666df6329 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 22:02:30 +0300 Subject: [PATCH 15/31] Support health checks for the services --- .config/containers/systemd/ollama.container | 3 +++ .config/containers/systemd/transmission.container | 3 +++ 2 files changed, 6 insertions(+) diff --git a/.config/containers/systemd/ollama.container b/.config/containers/systemd/ollama.container index b44121d..d47f626 100644 --- a/.config/containers/systemd/ollama.container +++ b/.config/containers/systemd/ollama.container @@ -7,6 +7,9 @@ AutoUpdate=registry ContainerName=ollama DropCapability=ALL Environment=OLLAMA_KEEP_ALIVE=10m +HealthCmd=ollama list +# HealthInterval=30s +# HealthStartPeriod=15s Image=docker.io/ollama/ollama:latest Network=ollama.network NoNewPrivileges=true diff --git a/.config/containers/systemd/transmission.container b/.config/containers/systemd/transmission.container index 1f2ec07..01f0446 100644 --- a/.config/containers/systemd/transmission.container +++ b/.config/containers/systemd/transmission.container @@ -7,6 +7,9 @@ AutoUpdate=registry ContainerName=transmission Environment=PGID=1000 Environment=PUID=1000 +HealthCmd=curl --fail --silent http://localhost:9091/ +# HealthInterval=30s +# HealthStartPeriod=30s Image=lscr.io/linuxserver/transmission:latest Network=private PodmanArgs=--pull=newer --transient-store From e72fe95497a8cf62508afcd9f5783c743878bccc Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 23:17:56 +0300 Subject: [PATCH 16/31] Create periodic healthcheck units for the transient store --- .config/setup/14-install-cron-jobs.sh | 2 ++ .config/systemd/user/podman-healthcheck@.service | 6 ++++++ .config/systemd/user/podman-healthcheck@.timer | 11 +++++++++++ 3 files changed, 19 insertions(+) create mode 100644 .config/systemd/user/podman-healthcheck@.service create mode 100644 .config/systemd/user/podman-healthcheck@.timer diff --git a/.config/setup/14-install-cron-jobs.sh b/.config/setup/14-install-cron-jobs.sh index 22851b8..df7b93d 100755 --- a/.config/setup/14-install-cron-jobs.sh +++ b/.config/setup/14-install-cron-jobs.sh @@ -5,6 +5,8 @@ IFS=$'\n\t' # keep-sorted start systemctl --user enable --now backup.timer +systemctl --user enable --now podman-healthcheck@ollama.timer +systemctl --user enable --now podman-healthcheck@transmission.timer systemctl --user enable --now sync-backup.timer systemctl --user enable --now sync-git-repos.timer # keep-sorted end diff --git a/.config/systemd/user/podman-healthcheck@.service b/.config/systemd/user/podman-healthcheck@.service new file mode 100644 index 0000000..b521d85 --- /dev/null +++ b/.config/systemd/user/podman-healthcheck@.service @@ -0,0 +1,6 @@ +[Unit] +Description=Podman health check for %i + +[Service] +Type=oneshot +ExecStart=podman --transient-store healthcheck run %i diff --git a/.config/systemd/user/podman-healthcheck@.timer b/.config/systemd/user/podman-healthcheck@.timer new file mode 100644 index 0000000..255104d --- /dev/null +++ b/.config/systemd/user/podman-healthcheck@.timer @@ -0,0 +1,11 @@ +[Unit] +Description=Podman health check timer for %i +BindsTo=%i.service +After=%i.service + +[Timer] +OnActiveSec=30s +OnUnitActiveSec=30s + +[Install] +WantedBy=%i.service From 5e559aa2a9d31cfb6614a04ce2b14ccfde567e8d Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sun, 12 Apr 2026 22:45:39 +0300 Subject: [PATCH 17/31] Use a widely-available terminal config in SSH remotes --- .ssh/config.d/90-terminal-emulator.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .ssh/config.d/90-terminal-emulator.conf diff --git a/.ssh/config.d/90-terminal-emulator.conf b/.ssh/config.d/90-terminal-emulator.conf new file mode 100644 index 0000000..a11d57f --- /dev/null +++ b/.ssh/config.d/90-terminal-emulator.conf @@ -0,0 +1,2 @@ +Host * + SetEnv TERM=xterm-256color From 8c53e540d85e47c5a8471ea34c815088f9a873e4 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Mon, 13 Apr 2026 08:13:06 +0300 Subject: [PATCH 18/31] Ignore local Claude Code files globally --- .gitconfig | 2 ++ .gitignore_global | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 .gitignore_global diff --git a/.gitconfig b/.gitconfig index d269033..92ad45b 100644 --- a/.gitconfig +++ b/.gitconfig @@ -20,3 +20,5 @@ # keep-sorted end [include] path = .hostgitconfig +[core] + excludesfile = ~/.gitignore_global diff --git a/.gitignore_global b/.gitignore_global new file mode 100644 index 0000000..1a88ff4 --- /dev/null +++ b/.gitignore_global @@ -0,0 +1,3 @@ +/conversation-id.txt +/conversation-id-*.txt +/.claude/settings.local.json From 5910825ca90dd4a490134c954105038e35200099 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 9 Apr 2026 22:02:10 +0300 Subject: [PATCH 19/31] Restrict service resource usage --- .config/containers/systemd/plantuml.container | 4 ++++ .config/containers/systemd/transmission.container | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.config/containers/systemd/plantuml.container b/.config/containers/systemd/plantuml.container index 47e0f49..b4fa46a 100644 --- a/.config/containers/systemd/plantuml.container +++ b/.config/containers/systemd/plantuml.container @@ -18,4 +18,8 @@ ReadOnly=true WantedBy=default.target [Service] +# keep-sorted start +CPUQuota=100% +MemoryMax=1G Restart=always +# keep-sorted end diff --git a/.config/containers/systemd/transmission.container b/.config/containers/systemd/transmission.container index 01f0446..91349ac 100644 --- a/.config/containers/systemd/transmission.container +++ b/.config/containers/systemd/transmission.container @@ -28,10 +28,12 @@ WantedBy=default.target [Service] # keep-sorted start +CPUQuota=200% ExecStartPre=mkdir --parents %h/.config/transmission ExecStartPre=mkdir --parents %h/Downloads/transmission ExecStartPre=mkdir --parents %h/Downloads/transmission/complete ExecStartPre=mkdir --parents %h/Downloads/transmission/incomplete ExecStartPre=mkdir --parents %h/Downloads/transmission/watch +MemoryMax=512M Restart=always # keep-sorted end From 4dd9795b0b89dd7fa7faf27e6ed193068fc3d573 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Fri, 10 Apr 2026 00:25:09 +0300 Subject: [PATCH 20/31] Mirror resource limits in podman as well --- .config/containers/systemd/plantuml.container | 2 +- .config/containers/systemd/transmission.container | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/containers/systemd/plantuml.container b/.config/containers/systemd/plantuml.container index b4fa46a..8fa35df 100644 --- a/.config/containers/systemd/plantuml.container +++ b/.config/containers/systemd/plantuml.container @@ -9,7 +9,7 @@ DropCapability=ALL Image=docker.io/plantuml/plantuml-server:jetty Network=private NoNewPrivileges=true -PodmanArgs=--pull=newer --transient-store +PodmanArgs=--cpus 1 --memory 1g --pull=newer --transient-store PublishPort=127.0.0.1:8080:8080 ReadOnly=true # keep-sorted end diff --git a/.config/containers/systemd/transmission.container b/.config/containers/systemd/transmission.container index 91349ac..daeee81 100644 --- a/.config/containers/systemd/transmission.container +++ b/.config/containers/systemd/transmission.container @@ -12,7 +12,7 @@ HealthCmd=curl --fail --silent http://localhost:9091/ # HealthStartPeriod=30s Image=lscr.io/linuxserver/transmission:latest Network=private -PodmanArgs=--pull=newer --transient-store +PodmanArgs=--cpus 2 --memory 512m --pull=newer --transient-store PublishPort=127.0.0.1:9091:9091 PublishPort=51413:51413 PublishPort=51413:51413/udp From 69d53d4d8a5a0c36469fbf12c4eabbbecf43b676 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Thu, 16 Apr 2026 03:47:59 +0300 Subject: [PATCH 21/31] Increase the cache TTL for loaded models --- .config/containers/systemd/ollama.container | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.config/containers/systemd/ollama.container b/.config/containers/systemd/ollama.container index d47f626..500baad 100644 --- a/.config/containers/systemd/ollama.container +++ b/.config/containers/systemd/ollama.container @@ -6,7 +6,7 @@ Description=A local LLM server AutoUpdate=registry ContainerName=ollama DropCapability=ALL -Environment=OLLAMA_KEEP_ALIVE=10m +Environment=OLLAMA_KEEP_ALIVE=30m HealthCmd=ollama list # HealthInterval=30s # HealthStartPeriod=15s From 48c5b4e00e81c017b5f2191c97b77a4c5aa390c6 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:43:13 +0300 Subject: [PATCH 22/31] Add Gemma 4 to the model library --- .config/emacs/site-lisp/local-models.el | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.config/emacs/site-lisp/local-models.el b/.config/emacs/site-lisp/local-models.el index ac695eb..bc9402d 100644 --- a/.config/emacs/site-lisp/local-models.el +++ b/.config/emacs/site-lisp/local-models.el @@ -11,6 +11,14 @@ :context-window 128 :cutoff-date "2024-08" ) + ( + gemma4:latest + :description "A model from Google built on Gemini technology" + :capabilities (media tool-use cache) + :mime-types ("image/bmp" "image/gif" "image/jpeg" "image/png" "image/tiff" "image/webp") + :context-window 128 + :cutoff-date "2025-01" + ) ( hf.co/Orenguteng/Llama-3.1-8B-Lexi-Uncensored-V2-GGUF:latest :description "Uncensored model based on Llama-3.1-8b-Instruct" From d3c941a8c1b9b71c5aea4eb152cd74d8c6ad1a6f Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:51:36 +0300 Subject: [PATCH 23/31] Elaborate on outlier cases in the testing instructions --- .claude/CLAUDE.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 5f4fcab..3dcbbfb 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -55,6 +55,14 @@ Why this matters: When adding or modifying code, verify that tests cover the new logic. If coverage drops, add tests before merging. +### Coverage Exclusions and Test Quality + +**Pure I/O code is excluded from coverage requirements.** Code whose sole purpose is performing I/O (reading files, making network calls, rendering output) cannot be effectively tested without manual interaction. However, this has a direct design implication: keep the I/O layer as thin and trivial as possible. All business logic, validation, transformation, and decision-making must live in testable modules that the I/O layer merely calls into. A fat I/O layer is a design smell, not an excuse for missing tests. + +**When business logic is tightly coupled to real I/O**, and separating them would genuinely undermine testability (not just convenience), prefer integration tests against an emulated service dedicated for testing. The emulated service must have reliable compatibility with the real target. For example, S3-dependent code can use MinIO via testcontainers or similar tooling to run tests that genuinely need I/O access. This approach is preferable to either mocking away the I/O (which hides real failure modes) or leaving the logic untested. + +**Tests must exercise actual code paths, not reproduce them.** In rare cases, code is so trivial that the only apparent way to test it is to restate it in the test. Such tests verify nothing — they pass by construction and remain passing even when the code changes, which demonstrates that they provide no actual validation. Do not write these. Instead, explicitly exclude the code from coverage. Note that this situation is rare and usually signals a design gap (logic that should be extracted or combined with something more substantive) rather than inherent untestability. + ## CLI Style **Prefer long option names over short ones** in command-line applications and examples. From ff76aaf5255c08c8d397cc26c0c58807cab46102 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:52:23 +0300 Subject: [PATCH 24/31] Clarify the role of integration testing for code that requires I/O --- .claude/CLAUDE.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 3dcbbfb..2ecdf09 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -59,7 +59,11 @@ When adding or modifying code, verify that tests cover the new logic. If coverag **Pure I/O code is excluded from coverage requirements.** Code whose sole purpose is performing I/O (reading files, making network calls, rendering output) cannot be effectively tested without manual interaction. However, this has a direct design implication: keep the I/O layer as thin and trivial as possible. All business logic, validation, transformation, and decision-making must live in testable modules that the I/O layer merely calls into. A fat I/O layer is a design smell, not an excuse for missing tests. -**When business logic is tightly coupled to real I/O**, and separating them would genuinely undermine testability (not just convenience), prefer integration tests against an emulated service dedicated for testing. The emulated service must have reliable compatibility with the real target. For example, S3-dependent code can use MinIO via testcontainers or similar tooling to run tests that genuinely need I/O access. This approach is preferable to either mocking away the I/O (which hides real failure modes) or leaving the logic untested. +**The value of integration testing for I/O is context-dependent** — it depends on whether I/O is incidental to the component or central to its purpose. + +When I/O is incidental (e.g., an application that loads configuration from a file), there is no value in testing the file-reading call itself — trust the language's I/O primitives. Instead, feed raw data to a pure function that handles parsing and validation. In some cases even parsing tests may be unnecessary, such as a JSON config file loaded via a standard-library routine that directly constructs application-defined structs. Structure such code to confine I/O in a short routine that can be excluded from coverage. + +When I/O *is* the core business logic (e.g., a database engine or FUSE filesystem), it must be thoroughly integration-tested against a functioning backend. The I/O layer cannot be excluded here because it is the component's reason for existing. Provision appropriate test infrastructure: a tmpfs filesystem for storage-centric tests, an Alpine testcontainer for cases that need to exercise interactions between different user permissions, or an emulated service with reliable compatibility to the real target (e.g., MinIO via testcontainers for S3-dependent code). This is preferable to either mocking away the I/O (which hides real failure modes) or leaving the logic untested. **Tests must exercise actual code paths, not reproduce them.** In rare cases, code is so trivial that the only apparent way to test it is to restate it in the test. Such tests verify nothing — they pass by construction and remain passing even when the code changes, which demonstrates that they provide no actual validation. Do not write these. Instead, explicitly exclude the code from coverage. Note that this situation is rare and usually signals a design gap (logic that should be extracted or combined with something more substantive) rather than inherent untestability. From 2be49fd182b4c6757a4f5d9863ccd7010512dd7b Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:54:03 +0300 Subject: [PATCH 25/31] Describe the preferred setup of green-field projects --- .claude/CLAUDE.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 2ecdf09..01d353d 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -80,3 +80,31 @@ command -v -o file.txt ``` Long options are self-documenting and make scripts and examples easier to understand without consulting help text. Short options are acceptable for interactive use but should not appear in committed code, documentation, or examples. + +## Green-Field Project Setup + +When setting up a new project, code-quality and developer-experience tooling must be included from the start and integrated into the development workflow. The principles below use Python as a concrete example, but apply generally to any language ecosystem. + +### Python Tooling + +Use **uv** to manage dependencies and create the project virtual environment. All work must be performed inside the venv. Additionally, install and configure the **pre-commit** hook manager with a baseline DevEx toolset: + +- **ruff** — linting and formatting +- **mypy** — static type checking +- **tach** — structural/dependency boundary checks + +Configure all tools for their strictest check levels by default. Include a `py.typed` marker file in every package to signal PEP 561 compliance. + +### Line Length + +Do not manually break lines to conform to a line-length limit. Automated code formatters (ruff, gofmt, etc.) handle this for source code. Write unbroken lines in text and Markdown files (e.g., README.md) as well. This also applies to one-off files outside of a project context. + +### Licensing (REUSE) + +In all projects, install a **pre-commit hook for the REUSE tool** to lint licensing information and ensure every file has correct SPDX headers. + +Default license assignments: + +- **GPL-3.0-or-later** — source code files in coding projects +- **CC-BY-SA-4.0** — documentation files (README, user guides, etc.); also the default project license for non-coding projects +- **CC0-1.0** — project configuration files (e.g., `pyproject.toml`, `tach.toml`) and small utility scripts or Makefiles that are not core to the implemented logic From 575976e578ac64caf888f6da0e1e7fcf6d5b204e Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:55:06 +0300 Subject: [PATCH 26/31] Invite creative writing in source code --- .claude/CLAUDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 01d353d..f3e8fbf 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -40,6 +40,8 @@ Style preferences (when not conflicting with existing patterns): - Avoid mutation of inputs - Pure functions where practical +**Fun is welcome in moderation.** Clarity and readability come first, but the occasional reference, joke, or creative naming makes code more enjoyable to read and write. The key constraint: it must be apropos to the actual code — no random remarks. A comment that winks at a known falsehood the code knowingly embraces, or a function name that doubles as a cultural reference while accurately describing its behavior, are both fair game. Keep it sparse; if every function has a quip, none of them land. + **Style changes should be separate from implementation.** If you notice style inconsistencies or want to improve patterns, do so in dedicated refactor commits or branches rather than mixing with feature work. ## Test Coverage From 6029206d1b0654cbbda030fafdeda6e38c84df96 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:55:24 +0300 Subject: [PATCH 27/31] Add guidelines for naming and magic numbers in tests --- .claude/CLAUDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index f3e8fbf..f139d3e 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -42,6 +42,8 @@ Style preferences (when not conflicting with existing patterns): **Fun is welcome in moderation.** Clarity and readability come first, but the occasional reference, joke, or creative naming makes code more enjoyable to read and write. The key constraint: it must be apropos to the actual code — no random remarks. A comment that winks at a known falsehood the code knowingly embraces, or a function name that doubles as a cultural reference while accurately describing its behavior, are both fair game. Keep it sparse; if every function has a quip, none of them land. +**Naming in test code** has different rules than implementation code. Implementation names must always be meaningful and reflective of purpose. Test code, however, may use metasyntactic variables when a value is arbitrary and meaningfulness would be misleading. Preferred metasyntactic names: `foo`, `bar`, `baz`, `frob`, `xyzzy`, and conjugations of `frobnicate`. For arbitrary magic numbers, prefer values with clean ternary representations (e.g., 72 or 243 over 128 or 255 when a test needs a fixed byte value). + **Style changes should be separate from implementation.** If you notice style inconsistencies or want to improve patterns, do so in dedicated refactor commits or branches rather than mixing with feature work. ## Test Coverage From d9d1ef0878e7d68a5292188907255809fdcc5aed Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sat, 18 Apr 2026 11:55:38 +0300 Subject: [PATCH 28/31] Integrate git into Claude's development process --- .claude/CLAUDE.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index f139d3e..bf4ddb2 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -85,6 +85,12 @@ command -v -o file.txt Long options are self-documenting and make scripts and examples easier to understand without consulting help text. Short options are acceptable for interactive use but should not appear in committed code, documentation, or examples. +## Git Workflow + +Assume you are working in a git repository. Partition changes into small, self-contained commits and commit each before proceeding to the next change. When enacting a plan, a single action item will often span several such commits — that is expected and preferred over bundling unrelated changes together. + +Leverage the git history during development as well. Git enables efficient and reliable rollbacks of recent changes or research dead ends, and clean reverts of specific diffs from earlier in the history. Prefer these over manual cleanup. + ## Green-Field Project Setup When setting up a new project, code-quality and developer-experience tooling must be included from the start and integrated into the development workflow. The principles below use Python as a concrete example, but apply generally to any language ecosystem. From d7e16e108d92f4b958b872652e019c2bc20e6a02 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sun, 19 Apr 2026 23:25:59 +0300 Subject: [PATCH 29/31] Permit Claude to restructure automatically-committed history --- .claude/CLAUDE.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index bf4ddb2..a35b7c3 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -91,6 +91,14 @@ Assume you are working in a git repository. Partition changes into small, self-c Leverage the git history during development as well. Git enables efficient and reliable rollbacks of recent changes or research dead ends, and clean reverts of specific diffs from earlier in the history. Prefer these over manual cleanup. +### Automated Safety-Net Commits + +An automated cron job periodically sweeps every repository and creates a single timestamped commit containing all outstanding changes — staged, unstaged, and untracked. Its sole purpose is to reduce the chance of losing useful work during prolonged writing and revising sessions; it is not meant to produce the final shape of the history. + +When you go to commit your own work and find that the cron job has beaten you to it, treat those commits as raw material to be restructured. Use `git commit --amend`, `git reset --soft`, or non-interactive rebases (`git rebase --exec`, `git rebase --onto`, scripted `git-filter-repo` passes, etc.) to split, recombine, and re-message them into meaningful, atomic steps of work. + +Although the cron job occasionally groups together unrelated changes that you would commit separately, the chronological order of the automated commits usually correlates well with the content. Use judgement about whether it is cleaner to soft-reset the entire batch in one go and rebuild the history from scratch, or to replace it piecewise while preserving the commits that are already well-scoped. + ## Green-Field Project Setup When setting up a new project, code-quality and developer-experience tooling must be included from the start and integrated into the development workflow. The principles below use Python as a concrete example, but apply generally to any language ecosystem. From d22b10a8ab018535f71a27d388200102e886e02b Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Sun, 19 Apr 2026 23:57:14 +0300 Subject: [PATCH 30/31] Teach Claude about the Three Virtues --- .claude/CLAUDE.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index a35b7c3..14f10e2 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -5,6 +5,34 @@ - When asked to do ONE thing, do exactly that. Do not proactively migrate dependencies, refactor adjacent code, or expand scope. You may suggest further edits, but wait for confirmation before any scope expansion. - Prefer the simplest, most localized solution. Changes should target the most-relevant section of code — for example, catch errors in the scope that best handles them rather than injecting data up or down the stack. Take time to think about the best approach rather than quickly jumping to an implementation. +## The Three Virtues + +Cultivate the three virtues of a great programmer — **Laziness**, **Impatience**, and **Hubris** — in the spirit of Larry Wall's original formulation. The first virtue deserves particular emphasis. + +**Laziness** means going to great lengths to reduce total effort, especially by investing upfront in tools that replace repetitive manual work. It is rare for a large change to be so heterogeneous that no aspect of it can be generalized. + +### Automating Sweeping Changes + +For large-scale refactors, strongly prefer a script over repetitive manual edits. Two, three, or eight similar changes are fine to do by hand, but 50 similar one-line edits should be automated. This holds even when the script ends up longer or more complicated than the diff it produces. + +The preferred workflow: + +1. Craft a utility that applies the transformation. Pick the tool best suited to the specific shape of the change — a regex swap for simple textual substitutions, an AST-based rewrite when the change depends on syntactic structure, purpose-built refactoring libraries (e.g. `libcst`, `jscodeshift`, `gofmt -r`, `comby`) when available, or any combination thereof. +2. Commit the script on its own. +3. Run it and commit the results as a separate commit. + +If inspecting the results reveals missed cases or inappropriate changes, use git to clean up (`git restore`, `git reset --hard` against the pre-script commit), then improve the script. Commit improvements as follow-ups, or amend the script's commit for trivial bug fixes, and re-run. + +### Why This Matters for Review + +A refactor script plus a spot-check of its output is far easier to review than a diff of 50 manual edits. The reviewer can be convinced of the logical correctness of the script and sample its results, rather than verifying every edit individually and separately confirming that no instances were accidentally skipped. + +### Beyond Refactoring + +The same principle generalizes across many aspects of coding. Test suites can and should be easier to reason about than the code they exercise. Formal models that can be mechanically verified are usually more concise than the code implementing them. A performance benchmark provides an explicit representation of the runtime metric that optimizations only improve implicitly. + +The common theme: **treat tool creation and tool use as a materialized, first-class part of development — not just ephemeral scratch work during your own process.** Show your work and publish it into the history. + ## Tool Usage Preferences For simple factual lookups (package versions, release dates), use targeted, purpose-built commands and local CLI tools first before attempting web searches — e.g. `pip index versions ` for Python, `npm view versions` for Node. Prefer fast local approaches over web research. From 326b65f507dd1dd51c048983d06a4856be8f6c42 Mon Sep 17 00:00:00 2001 From: Ohad Livne Date: Mon, 20 Apr 2026 00:05:28 +0300 Subject: [PATCH 31/31] Elaborate on the iterative process for refactor scripts --- .claude/CLAUDE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 14f10e2..fa6545c 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -23,6 +23,11 @@ The preferred workflow: If inspecting the results reveals missed cases or inappropriate changes, use git to clean up (`git restore`, `git reset --hard` against the pre-script commit), then improve the script. Commit improvements as follow-ups, or amend the script's commit for trivial bug fixes, and re-run. +Continue iterating until: + +- **(a) No incorrect changes are included in the diff.** This is a hard requirement — a script that produces even one wrong edit is not done. +- **(b) Either no missing cases remain, or the remaining cases are few and share too little in common for their inclusion in the script to be easier to validate than just editing them by hand.** When a handful of outlier cases survive the automated pass, handle them in a dedicated commit, separate from both the script-creation commit and the script-execution commit. + ### Why This Matters for Review A refactor script plus a spot-check of its output is far easier to review than a diff of 50 manual edits. The reviewer can be convinced of the logical correctness of the script and sample its results, rather than verifying every edit individually and separately confirming that no instances were accidentally skipped.