Configures git hooks for automated testing, linting, and quality enforcement. Use when initializing projects, establishing quality gates, or preventing commit/push errors.
Configures Git hooks to automatically run tests, linting, and formatting before commits and pushes.
npx claudepluginhub bacchus-labs/wranglerThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/detailed-guide.mdtemplates/PATTERN_B_README.mdtemplates/commit-msg.template.shtemplates/hooks-config.default.jsontemplates/hooks-config.go.jsontemplates/hooks-config.javascript.jsontemplates/hooks-config.python.jsontemplates/hooks-config.schema.jsontemplates/install-hooks.shtemplates/pre-commit.template.shtemplates/pre-push.template.shtemplates/pull_request_template.mdThis skill sets up Git hooks to automatically enforce testing and code quality standards before commits and pushes. It supports two installation patterns:
.git/hooks/ with configuration in .wrangler/config/hooks-config.json.wrangler/config/git-hooks/ with install script for team synchronizationStep 1: Verify Git Repository
# Check if we're in a git repository
git rev-parse --show-toplevel
# Check existing hooks
ls -la .git/hooks/ 2>/dev/null | head -10
# Check for existing wrangler hooks config
[ -f .wrangler/config/hooks-config.json ] && echo "Existing config found" || echo "No existing config"
If not in a git repository, inform user and exit.
Step 2: Check for Existing Hook Managers
# Check for Husky
[ -d .husky ] && echo "Husky detected" || true
[ -f package.json ] && grep -q '"husky"' package.json && echo "Husky in package.json" || true
# Check for pre-commit framework
[ -f .pre-commit-config.yaml ] && echo "pre-commit framework detected" || true
# Check for existing custom hooks
for hook in pre-commit pre-push commit-msg; do
[ -f .git/hooks/$hook ] && echo "Existing $hook hook found" || true
done
If existing hook manager found, ask user how to proceed:
If the skill detects an empty project or no test framework:
Detection criteria:
Graceful handling:
Populate TESTING.md with placeholder content:
TESTING.md should already exist from governance initialization. Update status section:
**Status:** No tests configured yet
If TESTING.md doesn't exist, create it from initializing-governance template first.
Create stub hooks-config.json:
{
"version": "1.0.0",
"createdAt": "2026-01-21T...",
"testCommand": "",
"note": "No tests detected. Run /wrangler:updating-git-hooks after adding tests.",
"protectedBranches": ["main", "master", "feature/*", "fix/*"],
"skipDocsOnlyChanges": true,
"docsPatterns": ["*.md", "docs/**/*", ".wrangler/memos/**/*"],
"bypassEnvVar": "WRANGLER_SKIP_HOOKS",
"setupComplete": false
}
Note: File should be created at .wrangler/config/hooks-config.json
Install bypass-only hooks:
setupComplete flag in configInform user:
Git hooks installed (inactive - no tests detected)
Hooks are installed but will not enforce testing until you:
1. Add tests to your project
2. Run: /wrangler:updating-git-hooks
Created:
- .wrangler/TESTING.md (placeholder)
- .wrangler/config/hooks-config.json (stub configuration)
- .git/hooks/pre-commit (bypass mode)
- .git/hooks/pre-push (bypass mode)
Why this works:
Step 3: Detect Project Type
Use Bash to identify project language/framework:
# JavaScript/TypeScript
[ -f package.json ] && echo "javascript"
# Python
[ -f setup.py ] || [ -f pyproject.toml ] || [ -f requirements.txt ] && echo "python"
# Go
[ -f go.mod ] && echo "go"
# Rust
[ -f Cargo.toml ] && echo "rust"
# Java
[ -f pom.xml ] || [ -f build.gradle ] && echo "java"
Step 4: Detect Existing Test/Format/Lint Commands
For JavaScript projects:
# Read package.json scripts
cat package.json | grep -E '"(test|lint|format)"' || true
For Python projects:
# Check for common test runners
[ -f pytest.ini ] || [ -f pyproject.toml ] && grep -q pytest pyproject.toml && echo "pytest"
[ -f setup.cfg ] && grep -q flake8 setup.cfg && echo "flake8"
For Go projects:
# Go has standard commands
echo "go test ./..."
echo "go fmt ./..."
Step 5: Ask User for Configuration
Use multiple AskUserQuestion calls to gather configuration:
Question 1: Installation Pattern
AskUserQuestion({
questions: [{
question: "Which hook installation pattern would you prefer?",
header: "Installation Pattern",
options: [
{
label: "Pattern A: Direct installation (Recommended)",
description: "Hooks in .git/hooks/, config in .wrangler/config/hooks-config.json"
},
{
label: "Pattern B: Version-controlled",
description: "Hooks in .wrangler/config/git-hooks/, install script for team sync"
}
],
multiSelect: false
}]
})
Question 2: Test Command
// Show detected commands as suggestions
AskUserQuestion({
questions: [{
question: "What command runs your full test suite?",
header: "Test Command",
options: [
{ label: "[detected command]", description: "Detected from project files" },
{ label: "Custom command", description: "I'll specify my own" }
],
multiSelect: false
}]
})
If "Custom command" selected, ask user to type the command.
Question 3: Unit Test Command (Optional)
AskUserQuestion({
questions: [{
question: "Do you have a separate command for fast unit tests? (for pre-commit)",
header: "Unit Tests",
options: [
{ label: "Same as full tests", description: "Use full test command" },
{ label: "[suggested fast command]", description: "Faster subset of tests" },
{ label: "Custom command", description: "I'll specify my own" },
{ label: "Skip unit tests", description: "Don't run tests in pre-commit" }
],
multiSelect: false
}]
})
Question 4: Format Command (Optional)
AskUserQuestion({
questions: [{
question: "What command formats your code? (auto-fix and re-stage)",
header: "Formatter",
options: [
{ label: "[detected command]", description: "Detected from project files" },
{ label: "Custom command", description: "I'll specify my own" },
{ label: "Skip formatting", description: "Don't auto-format in pre-commit" }
],
multiSelect: false
}]
})
Question 5: Lint Command (Optional)
AskUserQuestion({
questions: [{
question: "What command lints your code?",
header: "Linter",
options: [
{ label: "[detected command]", description: "Detected from project files" },
{ label: "Custom command", description: "I'll specify my own" },
{ label: "Skip linting", description: "Don't lint in pre-commit" }
],
multiSelect: false
}]
})
Question 6: Protected Branches
AskUserQuestion({
questions: [{
question: "Which branches should require full tests before push?",
header: "Protected Branches",
options: [
{ label: "Default (main, master, develop, release/*, hotfix/*)", description: "Standard Git Flow branches" },
{ label: "Just main/master", description: "Only primary branches" },
{ label: "Custom patterns", description: "I'll specify my own" }
],
multiSelect: false
}]
})
Question 7: Commit Message Validation (Optional)
AskUserQuestion({
questions: [{
question: "Enable commit message format validation?",
header: "Commit Messages",
options: [
{ label: "Yes - Conventional Commits", description: "feat:, fix:, docs:, etc." },
{ label: "No", description: "Allow any commit message format" }
],
multiSelect: false
}]
})
Step 6: Generate hooks-config.json
Create the configuration file with user's answers:
mkdir -p .wrangler/config
Use Write tool to create .wrangler/config/hooks-config.json:
{
"$schema": "https://wrangler.dev/schemas/hooks-config.json",
"version": "1.0.0",
"createdAt": "[ISO timestamp]",
"projectType": "[detected type]",
"testCommand": "[user's test command]",
"unitTestCommand": "[user's unit test command or null]",
"formatCommand": "[user's format command or null]",
"lintCommand": "[user's lint command or null]",
"protectedBranches": ["main", "master", "develop", "release/*", "hotfix/*"],
"skipDocsOnlyChanges": true,
"docsPatterns": ["*.md", "*.txt", "*.rst", "docs/*", "README*", "LICENSE*", "CHANGELOG*"],
"enableCommitMsgValidation": [true/false],
"bypassEnvVar": "WRANGLER_SKIP_HOOKS",
"pattern": "[A or B]"
}
Step 7: Install Hooks (Pattern A)
If Pattern A selected:
# Backup existing hooks
if [ -f .git/hooks/pre-commit ] || [ -f .git/hooks/pre-push ]; then
mkdir -p .git/hooks.backup
cp .git/hooks/pre-commit .git/hooks.backup/ 2>/dev/null || true
cp .git/hooks/pre-push .git/hooks.backup/ 2>/dev/null || true
cp .git/hooks/commit-msg .git/hooks.backup/ 2>/dev/null || true
echo "Existing hooks backed up to .git/hooks.backup/"
fi
Use Read tool to read template files from wrangler skills directory:
skills/setting-up-git-hooks/templates/pre-commit.template.shskills/setting-up-git-hooks/templates/pre-push.template.shskills/setting-up-git-hooks/templates/commit-msg.template.sh (if enabled)Use string replacement to substitute placeholders:
{{TEST_COMMAND}} -> user's test command{{UNIT_TEST_COMMAND}} -> user's unit test command{{FORMAT_COMMAND}} -> user's format command{{LINT_COMMAND}} -> user's lint command{{PROTECTED_BRANCHES}} -> user's protected branches{{DOCS_PATTERNS}} -> docs patternsUse Write tool to save hooks to .git/hooks/:
.git/hooks/pre-commit.git/hooks/pre-push.git/hooks/commit-msg (if enabled)Make hooks executable:
chmod +x .git/hooks/pre-commit
chmod +x .git/hooks/pre-push
[ -f .git/hooks/commit-msg ] && chmod +x .git/hooks/commit-msg
Step 8: Install Hooks (Pattern B)
If Pattern B selected:
# Create version-controlled hooks directory
mkdir -p .wrangler/config/git-hooks
Use Write tool to save hooks to .wrangler/config/git-hooks/:
.wrangler/config/git-hooks/pre-commit.wrangler/config/git-hooks/pre-push.wrangler/config/git-hooks/commit-msg (if enabled)Use Write tool to create install script at scripts/install-hooks.sh:
(Copy from skills/setting-up-git-hooks/templates/install-hooks.sh)
Make files executable:
chmod +x .wrangler/config/git-hooks/pre-commit
chmod +x .wrangler/config/git-hooks/pre-push
[ -f .wrangler/config/git-hooks/commit-msg ] && chmod +x .wrangler/config/git-hooks/commit-msg
chmod +x scripts/install-hooks.sh
Run install script:
./scripts/install-hooks.sh
Step 9: Install PR Template
Create PR template in user's project:
mkdir -p .github
Create PR template (git hooks specific):
.github/pull_request_template.md (copy from skills/setting-up-git-hooks/templates/pull_request_template.md)Note on other templates: Security checklist and Definition of Done templates remain in their skill directories:
skills/initializing-governance/templates/SECURITY_CHECKLIST.mdskills/initializing-governance/templates/DEFINITION_OF_DONE.mdThese are referenced directly from skills, not copied to project directories.
Step 10: Populate TESTING.md
TESTING.md is created by initializing-governance skill. This step populates it with git hooks configuration.
If .wrangler/TESTING.md doesn't exist (governance not initialized), create it from initializing-governance template with user's configuration:
# Copy template from initializing-governance
cp skills/initializing-governance/templates/TESTING.md .wrangler/TESTING.md
Then populate all placeholders with detected/configured values.
Step 11: Verify Installation
# Verify hooks are installed and executable
echo "=== Hook Installation Verification ==="
for hook in pre-commit pre-push commit-msg; do
if [ -f .git/hooks/$hook ]; then
if [ -x .git/hooks/$hook ]; then
echo "[OK] $hook installed and executable"
else
echo "[WARN] $hook installed but not executable"
fi
else
echo "[SKIP] $hook not installed"
fi
done
# Verify config file
## References
For detailed information, see:
- `references/detailed-guide.md` - Complete workflow details, examples, and troubleshooting