wordpress-hook-integration
Skill19 starsChanged 11 days agoMITView on GitHub
Use when creating or changing Claude Code hooks in this template (PreToolUse guards, PostToolUse reminders, SessionStart context), registering them in settings.json and hooks.json, or testing them. Keywords: agent hooks, PreToolUse, PostToolUse, SessionStart, Claude Code hooks, hook-io, deploy guard, workflow automation
- Reads credentials
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- block-pattern-creationSkill
- canva-to-fse-autonomous-workflowSkill
- create-blog-articleSkill
- figma-to-fse-autonomous-workflowSkill
- fse-block-theme-developmentSkill
- fse-pattern-first-architectureSkill
- indesign-conversionSkill
- lintSkill
- scaffold-blockSkill
- testSkill
- visual-qa-verificationSkill
- wordpress-internationalizationSkill
- wordpress-security-hardeningSkill
- wordpress-testing-workflowsSkill
- wp-cli-workflowsSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 2 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 45
Exit code: always 0. Exit 2 also blocks (stderr becomes the reason) but the hooks here never rely on it.
- Very specific: line 80
Every command that may fail inside $( ) gets || true.
- Distinctive: line 83
Never write files, make network requests or take longer than a few seconds.
- Distinctive: line 124
Never create hooks that run for more than a few seconds, modify files, make network requests, block silently, or run destructive operations.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Claude Code Hook Integration
Overview
Hooks are shell scripts Claude Code runs at lifecycle events. In this template they enforce the root-level layout, stop deploys and data loss for a human, check commits for hardcoded design values, and remind the model to run the quality gate. Every hook follows one contract, lives in .claude/hooks/, and has a test in tests/claude-code/hooks.test.mjs.
The authoritative reference is https://code.claude.com/docs/en/hooks. The repo-specific conventions are in .claude/rules/claude-code-conventions.md.
When to Use
- Adding a guard or reminder that should run for every agent
- Changing what a hook catches, or its message
- Registering a hook for the plugin build (
hooks.json) as well as the project (settings.json) - Writing or fixing a hook test
Current Hook Architecture
Project hooks, registered in .claude/settings.json and mirrored in .claude/hooks/hooks.json for plugin installs:
| Hook | Event | What it does |
validate-theme-location.sh | PreToolUse Write|Edit|NotebookEdit | Denies writes under wp-content/(themes|plugins|mu-plugins)/ with the corrected root-level path. Enforces only in a repo with a root themes/ and nothing tracked under wp-content/. |
deploy-guard.sh | PreToolUse Bash (onFailure: block) | Asks before deploy.sh --env production, any rollback.sh, wp --ssh=, remote ssh/scp/rsync writes, docker compose down -v, wp db reset; reminds on a staging deploy; denies all of it inside a subagent. |
agent-no-deploy.sh | agent frontmatter PreToolUse Bash | deploy-guard.sh --subagent, for deployment-agent and devops-automator. |
pre-commit-token-guard.sh | PreToolUse Bash, if: "Bash(git commit *)" | Asks when a theme template, part or pattern the commit carries has a hex colour, pixel spacing, pixel font-size or font-family in a style attribute or block JSON. |
bundle-size-guard.sh | PreToolUse Bash, if: "Bash(git commit *)" | Reminder when a theme over 5120 KB or a plugin over 10240 KB is in the commit. |
post-bash-reminders.sh <case> | PostToolUse Bash, one if: per case | build-qa, coverage, dark-mode, mutation reminders after standards checks, PHPUnit/Pest runs and visual diffs. |
session-context.sh | SessionStart startup|resume|clear|compact | Plain-text status: conversion runs in flight, themes, Docker, .env, branch, stray wp-content/ files. Silent outside a Flavian checkout. |
figma-fse-post-template.sh, figma-fse-completion.sh | run by the converter agent through Bash | Per-template validation and the completion report under .claude/reports/. |
Agent-scoped hooks live in each agent's frontmatter (hooks:) and point at scripts/<agent>/*.sh or the project hooks through bash "$CLAUDE_PROJECT_DIR"/.... Plugin agents ignore frontmatter hooks, so anything that must hold in a plugin install is registered at the settings level too.
Shared code: .claude/hooks/lib/hook-io.sh (the contract: readers and JSON emitters) and .claude/hooks/lib/flavian-helpers.sh (Bash output, commit detection, the files a commit carries).
The Contract
- Input: the event as JSON on stdin. Common fields:
hook_event_name,cwd,permission_mode,session_id;agent_idandagent_typewhen the hook fires inside a subagent. Tool events addtool_name,tool_input(commandfor Bash,file_pathfor Write/Edit) and, after the tool ran,tool_response. - Output: one JSON object on stdout, or nothing. SessionStart hooks may print plain text, which is added to context.
- Decisions: a PreToolUse hook blocks with
permissionDecision: "deny"or prompts with"ask", each with apermissionDecisionReason. A reminder isadditionalContext. A one-line user notice is a top-levelsystemMessage. - Exit code: always 0. Exit 2 also blocks (stderr becomes the reason) but the hooks here never rely on it. A hook that crashes must fail open:
set -uplustrap 'exit 0' ERR. - Not part of the contract:
$TOOL_INPUT,$TOOL_OUTPUT,CLAUDE_TOOL_INPUT. Hooks written against them never fire. - Where a hook cannot prompt (
bypassPermissions,dontAsk),hook_gate_decisionturns anaskinto adenythat says where to run the command instead.
Creating a New Hook
#!/usr/bin/env bash
# my-guard.sh — PreToolUse hook (matcher: Bash). One paragraph on what it stops and why.
#
# Input: the hook event as JSON on stdin. Output: JSON on stdout, or nothing.
# Always exits 0.
set -u
trap 'exit 0' ERR
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=lib/hook-io.sh
source "$HOOK_DIR/lib/hook-io.sh"
# shellcheck source=lib/flavian-helpers.sh
source "$HOOK_DIR/lib/flavian-helpers.sh"
hook_read_input # HOOK_EVENT, TOOL_NAME, TOOL_COMMAND, TOOL_FILE_PATH, TOOL_RESPONSE
hook_read_context # HOOK_PERMISSION_MODE, HOOK_AGENT_ID, HOOK_AGENT_TYPE, HOOK_CWD
[ "$TOOL_NAME" = "Bash" ] || exit 0
printf '%s' "$TOOL_COMMAND" | grep -Eq 'wp[[:space:]]+search-replace' || exit 0
printf '%s' "$TOOL_COMMAND" | grep -Eq -- '--dry-run' && exit 0
hook_gate_decision ask "Search-replace guard: this rewrites the database. Run it with --dry-run first."
exit 0Rules:
- Bash 3.2 compatible (macOS): no
grep -P,mapfile,${var,,}, GNUfind -printf. - Every command that may fail inside
$( )gets|| true; theERRtrap otherwise ends the hook silently. - Filter early and cheaply (tool name, a
caseon the command) before anything heavy. - Messages start with a stable tag (
Deploy guard:,Token guard:,[bundle-guard]) so tests and readers can find them. - Never write files, make network requests or take longer than a few seconds.
Registering a Hook
In .claude/settings.json (project) and .claude/hooks/hooks.json (plugin), with the same handlers:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(wp search-replace *)",
"command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/my-guard.sh",
"timeout": 10,
"statusMessage": "Checking the search-replace guard"
}
]
}hooks.json uses bash "${CLAUDE_PLUGIN_ROOT}/.claude/hooks/my-guard.sh". An if: holds one permission rule and keeps the hook from starting for unrelated commands. onFailure: "block" makes a guard fail closed; reminders keep the default. The registration test fails if the two files drift apart.
Testing Hooks
node --test tests/claude-code/hooks.test.mjsEach hook gets: the contract cases (unrelated event, empty stdin, malformed JSON, executable bit, skeleton present) through the HOOKS list, plus behaviour cases built with runHook(name, event, { cwd }), decision(out), reason(out) and context(out). Repos with the Flavian layout come from flavianRepo(); a repo that tracks wp-content/ from wpContentRepo(). A manual check:
printf '%s' '{"tool_name":"Write","tool_input":{"file_path":"wp-content/themes/x/style.css"}}' \
| CLAUDE_PROJECT_DIR="$PWD" bash .claude/hooks/validate-theme-location.sh
# {"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny", ...}}The conformance check (node scripts/claude-code-conformance.js) fails on a hook that reads positional TOOL_INPUT, lacks the ERR trap, or is registered under an unknown event or with a missing script.
No Exceptions
Never create hooks that run for more than a few seconds, modify files, make network requests, block silently, or run destructive operations. A guard asks a human; it does not act.
Integration with This Template
The hooks hold the template's hard rules at runtime for every agent: the root-level layout, no unreviewed deploy or data loss, no hardcoded design values in a commit. Agents that run their own validators (the three converters, the validators and auditors, the test and performance agents) declare those in their frontmatter and point at scripts/<agent>/.
Skill Version: 3.0.0 Last Updated: 2026-11-02
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

