Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .claude/hooks/_parse_input.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Shared helper: reads hook JSON from stdin and sets $cmd to the Bash tool command.
# Sources into each hook with: . "$(dirname "$0")/_parse_input.sh"
# Exits 0 (allow) if no JSON parser is available.

if command -v jq >/dev/null 2>&1; then
# shellcheck disable=SC2034 # cmd is used by the sourcing hook script
cmd=$(jq -r '.tool_input.command // ""' 2>/dev/null || echo "")
elif command -v python3 >/dev/null 2>&1; then
# shellcheck disable=SC2034 # cmd is used by the sourcing hook script
cmd=$(python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_input',{}).get('command',''))" 2>/dev/null || echo "")
else
exit 0
fi
13 changes: 13 additions & 0 deletions .claude/hooks/no-main-commits.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Project rule: never work directly on the main or master branch.
# Blocks: git commit when current branch is main or master.

# shellcheck source=/dev/null
. "$(dirname "$0")/_parse_input.sh"

if echo "$cmd" | grep -qE '(^|[;&|`(])[[:space:]]*(([[:alpha:]_][[:alnum:]_]*=[^[:space:]]*[[:space:]]+)*)([^[:space:]]*/)?git[[:space:]]+commit([[:space:]]|$|[;&|])'; then
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
if [ "$branch" = "main" ] || [ "$branch" = "master" ]; then
echo "{\"continue\":false,\"stopReason\":\"Project rule: never work directly on the $branch branch.\"}"
fi
fi
10 changes: 10 additions & 0 deletions .claude/hooks/no-pr-merge.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Project rule: never merge a pull request.
# Blocks: gh pr merge

# shellcheck source=/dev/null
. "$(dirname "$0")/_parse_input.sh"

if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*gh pr merge'; then
echo '{"continue":false,"stopReason":"Project rule: never merge a pull request."}'
fi
10 changes: 10 additions & 0 deletions .claude/hooks/no-push.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Project rule: never push a branch without explicit instruction.
# Blocks: git push

# shellcheck source=/dev/null
. "$(dirname "$0")/_parse_input.sh"

if echo "$cmd" | grep -qE '(^|[;&|`(])[[:space:]]*(([[:alpha:]_][[:alnum:]_]*=[^[:space:]]*[[:space:]]+)*)([^[:space:]]*/)?git[[:space:]]+push([[:space:]]|$|[;&|])'; then
echo '{"continue":false,"stopReason":"Project rule: never push a branch without explicit instruction."}'
fi
11 changes: 11 additions & 0 deletions .claude/hooks/no-rm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Project rule: never delete a file without explicit permission.
# Blocks: rm, sudo rm, xargs rm, /bin/rm, /usr/bin/rm (and similar absolute paths).
# Does not cover: find -exec rm (rm as a subprocess argument, not a shell token).

# shellcheck source=/dev/null
. "$(dirname "$0")/_parse_input.sh"

if echo "$cmd" | grep -qE '(^|[;&|])[[:space:]]*(sudo[[:space:]]+|xargs[[:space:]]+)?([^[:space:]]*/)?rm([[:space:]]|$)'; then
echo '{"continue":false,"stopReason":"Project rule: never delete a file without explicit permission."}'
fi
32 changes: 32 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/no-pr-merge.sh",
"timeout": 5,
"statusMessage": "Checking project rules..."
},
{
"type": "command",
"command": ".claude/hooks/no-main-commits.sh",
"timeout": 5
},
{
"type": "command",
"command": ".claude/hooks/no-push.sh",
"timeout": 5
},
{
"type": "command",
"command": ".claude/hooks/no-rm.sh",
"timeout": 5
}
]
}
]
}
}
2 changes: 2 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ If you change template behavior, update:

## Project Rules

- At the start of a coding session, review the repository structure and any relevant README or documentation files to understand the area you are working in.
- Always read the files relevant to the task before suggesting or making a change.
- Never merge a pull request.
- Never work directly on the `main` or `master` branch.
- Never push a branch without explicit instruction.
Expand Down
Loading