From: Jakub Czajka Date: Mon, 6 Jul 2026 10:23:44 +0000 (+0200) Subject: [ai] Replace guard-commands with block-builds, block, and create hooks. X-Git-Url: https://git.ekhem.eu.org/?a=commitdiff_plain;h=75dd09077684bdbcc7bcfb2896efec70e074f559;p=guix.git [ai] Replace guard-commands with block-builds, block, and create hooks. Splits the monolithic guard-commands hook into three single-purpose hooks with more granular matchers in settings.json. block-builds: Guards guix and make build/reconfigure commands. Asks on main, denies in for destructive operations (reconfigure, home-*, system-*). block: Denies git checkout/switch outright. Enforces Enter (must not already be in a ) and Exit (must not have unpushed commits diverging from main). Sends a desktop notification on Enter success. create: Uses a universal matcher ("*") to deny all tool calls on main unless already inside the session's . Allows Enter through to let the user enter an isolated session. --- diff --git a/.claude/hooks/block-builds b/.claude/hooks/block-builds new file mode 100755 index 0000000..253b13c --- /dev/null +++ b/.claude/hooks/block-builds @@ -0,0 +1,62 @@ +#!/bin/sh +# Copyright (c) 2026 Jakub Czajka +# License: GPL-3.0 or later. +# +# block-builds - Guard guix/make build/reconfigure. + +command=$($GUIX_BIN/sed --quiet \ + 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]\+\)".*/\1/p') +case "$command" in + *'guix home build'*|*'guix system build'*) + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "ask"' \ + '}}' + exit 0 + ;; + *'guix home reconfigure'*|*'guix system reconfigure'*) + if $GUIX_BIN/echo "$PWD" | $GUIX_BIN/grep -q '/worktrees/' + then + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "deny",' \ + ' "systemMessage": "🚫 Reconfigure only on main worktree."' \ + '}}' + exit 0 + fi + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "ask"' \ + '}}' + exit 0 + ;; + *'make build-'*) + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "ask"' \ + '}}' + exit 0 + ;; + *'make home-'*|*'make system-'*) + if $GUIX_BIN/echo "$PWD" | $GUIX_BIN/grep -q '/worktrees/' + then + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "deny",' \ + ' "systemMessage": "🚫 Reconfigure only on main worktree."' \ + '}}' + exit 0 + fi + $GUIX_BIN/echo \ + '{"hookSpecificOutput": {' \ + ' "hookEventName": "PreToolUse",' \ + ' "permissionDecision": "ask"' \ + '}}' + exit 0 + ;; +esac diff --git a/.claude/hooks/guard-commands b/.claude/hooks/guard-commands deleted file mode 100755 index 3962a77..0000000 --- a/.claude/hooks/guard-commands +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/sh -# Copyright (c) 2026 Jakub Czajka -# License: GPL-3.0 or later. -# -# guard-commands — PreToolUse hook that guards against dangerous or -# branch-inappropriate commands. - -cmd=$($GUIX_BIN/cat | $GUIX_BIN/sed --regexp-extended --quiet \ - 's/.*"command"\s*:\s*"([^"]+)".*/\1/p') -[ -z "$cmd" ] && exit 0 - -branch=$($HOME/.guix-home/profile/bin/git -C "$CLAUDE_PROJECT_DIR" \ - branch --show-current 2>/dev/null) - -# --- git checkout / git switch: deny everywhere --- -if $GUIX_BIN/echo "$cmd" | $GUIX_BIN/grep --extended-regexp --quiet \ - '\bgit (checkout|switch)\b'; then - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "deny",' \ - ' "systemMessage": "Branch switching disabled. Use EnterWorktree."' \ - '}}' - exit 0 -fi - -# --- make build-*: ask everywhere --- -if $GUIX_BIN/echo "$cmd" | $GUIX_BIN/grep --extended-regexp --quiet \ - '\bmake build-'; then - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "ask"' \ - '}}' - exit 0 -fi - -# --- guix build: ask everywhere --- -if $GUIX_BIN/echo "$cmd" | $GUIX_BIN/grep --extended-regexp --quiet \ - '\bguix (home|system) build\b'; then - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "ask"' \ - '}}' - exit 0 -fi - -# --- guix reconfigure: ask on main, deny on branches --- -if $GUIX_BIN/echo "$cmd" | $GUIX_BIN/grep --extended-regexp --quiet \ - '\bguix (home|system) reconfigure\b'; then - if [ "$branch" != "main" ]; then - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "deny",' \ - ' "systemMessage": "guix reconfigure blocked. Merge into main."' \ - '}}' - exit 0 - fi - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "ask"' \ - '}}' - exit 0 -fi - -# --- make home-* / make system-*: ask on main, deny on branches --- -if $GUIX_BIN/echo "$cmd" | $GUIX_BIN/grep --extended-regexp --quiet \ - '\bmake (home|system)-'; then - if [ "$branch" != "main" ]; then - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "deny",' \ - ' "systemMessage": "Reconfigure blocked. Merge into main."' \ - '}}' - exit 0 - fi - $GUIX_BIN/echo \ - '{"hookSpecificOutput": {' \ - ' "hookEventName": "PreToolUse",' \ - ' "permissionDecision": "ask"' \ - '}}' - exit 0 -fi - -exit 0 diff --git a/README b/README index 02dc15c..400401e 100644 --- a/README +++ b/README @@ -36,3 +36,10 @@ TODO 2. Update the version field in conf/home/claude-code.scm. 3. Add claude-code at the end, run guix build -f conf/home/claude-code.scm and get the correct hash from the "hash mismatch" error message. + +* Avoid merge conflicts when running multiple Claude Code instances. + + 1. Work on a separate branch per instance (e.g. claude-). + 2. Or use EnterWorktree for automatic isolation. + 3. Or add a PreToolUse hook that auto-creates/switches to a per-session + branch before Edit/Write.