Hook Development for Claude Code Plugins
anthropics/claude-plugins-official
Explains how to write Claude Code plugin hooks, both prompt-based checks and bash commands, for events such as PreToolUse, Stop and SessionStart.
PreToolUse fact-forcing gate that denies the first Edit/Write/Bash (including MultiEdit) attempt until the agent presents concrete facts (importers, data schemas, verbatim user instruction), then…
$ npx skills add affaan-m/ECC --skill gateguard -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install affaan-m/ECC gateguard --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/gateguard .claude/skills/gateguard && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .claude/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/affaan-m/ECC/tree/main/skills/gateguardType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add affaan-m/ECC --skill gateguard -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install affaan-m/ECC gateguard --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/gateguard .agents/skills/gateguard && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .agents/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add affaan-m/ECC --skill gateguard -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install affaan-m/ECC gateguard --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/gateguard .cursor/skills/gateguard && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .cursor/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/affaan-m/ECC.git --path skills/gateguard--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add affaan-m/ECC --skill gateguard -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install affaan-m/ECC gateguard --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/gateguard .gemini/skills/gateguard && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .gemini/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install affaan-m/ECC gateguardInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add affaan-m/ECC --skill gateguard -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/gateguard .github/skills/gateguard && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .github/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add affaan-m/ECC --skill gateguard -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install affaan-m/ECC gateguard --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/gateguard .opencode/skills/gateguard && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "gateguard" agent skill from https://github.com/affaan-m/ECC/tree/main/skills/gateguard into .opencode/skills/gateguard/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "gateguard", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
gateguardPreToolUse fact-forcing gate that denies the first Edit/Write/Bash (including MultiEdit) attempt until the agent presents concrete facts (importers, data schemas, verbatim user instruction), then…
Gateguard is an agent skill from affaan-m/ECC. PreToolUse fact-forcing gate that denies the first Edit/Write/Bash (including MultiEdit) attempt until the agent presents concrete facts (importers, data schemas, verbatim user instruction), then allows retry; A/B-tested at +2.25 quality points. Use when enabling or configuring the GateGuard hook, exempting paths via env vars, or handling first-touch denials.
Its SKILL.md is about 2.5k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It works with Bash. The repository describes itself as: The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond. The licence is MIT.
Read from SKILL.md and the folder at commit 4eb71d9. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitpipFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use git and pip, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Gateguard loads about 2.5k tokens when it runs. Until then it costs about 93 tokens; SKILL.md has 1,091 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from affaan-m/ECC at commit 4eb71d9, republished under its MIT licence (© affaan-m). 1,091 words, ~2,487 tokens.
.claude/skills/gateguard/SKILL.md (or your agent's skills folder).A PreToolUse hook that forces Claude to investigate before editing. Instead of self-evaluation ("are you sure?"), it demands concrete facts. The act of investigation creates awareness that self-evaluation never did.
LLM self-evaluation doesn't work. Ask "did you violate any policies?" and the answer is always "no." This is verified experimentally.
But asking "list every file that imports this module" forces the LLM to run Grep and Read. The investigation itself creates context that changes the output.
Three-stage gate:
1. DENY — block the first Edit/Write/Bash attempt
2. FORCE — tell the model exactly which facts to gather
3. ALLOW — permit retry after facts are presentedNo competitor does all three. Most stop at deny.
Two independent A/B tests, identical agents, same task:
| Task | Gated | Ungated | Gap |
|---|---|---|---|
| Analytics module | 8.0/10 | 6.5/10 | +1.5 |
| Webhook validator | 10.0/10 | 7.0/10 | +3.0 |
| Average | 9.0 | 6.75 | +2.25 |
Both agents produce code that runs and passes tests. The difference is design depth.
MultiEdit is handled identically — each file in the batch is gated individually.
Before editing {file_path}, present these facts:
1. List ALL files that import/require this file (search the tree — Glob/Grep, or find/grep via Bash)
2. List the public functions/classes affected by this change
3. If this file reads/writes data files, show field names, structure,
and date format (use redacted or synthetic values, not raw production data)
4. Quote the user's current instruction verbatimBefore creating {file_path}, present these facts:
1. Name the file(s) and line(s) that will call this new file
2. Confirm no existing file serves the same purpose (search the tree — Glob/Grep, or find/grep via Bash)
3. If this file reads/writes data files, show field names, structure,
and date format (use redacted or synthetic values, not raw production data)
4. Quote the user's current instruction verbatimTriggers on: rm -rf, git reset --hard, git push --force, drop table, etc.
1. List all files/data this command will modify or delete
2. Write a one-line rollback procedure
3. Quote the user's current instruction verbatim1. The current user request in one sentence
2. What this specific command verifies or producesThe first-touch gate evaluates each tool call independently. When several edits to a file that has not been touched yet are sent in one parallel batch, the first call is denied and the denial marks the file as checked, so the sibling edits in that batch are applied. Nothing is rolled back: the file can end up holding the sibling edits without the denied one.
The denial message names the file and warns that batch siblings may already have been applied. Treat it literally:
A batch-wide lock is not possible: hooks see tool calls one at a time, so the gate cannot know which calls arrived together.
The hook at scripts/hooks/gateguard-fact-force.js is included in this plugin. Enable it via hooks.json.
If GateGuard blocks setup or repair work, start the session with
ECC_GATEGUARD=off. For hook-level control, keep using
ECC_DISABLED_HOOKS with the GateGuard hook ID.
In long sessions, only the first GATEGUARD_FACT_FORCE_FULL_DENIALS
fact-force denials (default 3) emit the full four-fact block; later
denials are condensed to a single line carrying the denial ordinal, so
near-identical blocks cannot accumulate in the context window and
amplify model repetition loops (#2142). Retrying the same file or
command after presenting facts never re-triggers the gate.
ECC_GATEGUARD=off (or GATEGUARD_DISABLED=1) turns the gate off entirely.
The variables in this table do not — each narrows one behaviour while the
load-bearing destructive-Bash checks keep running:
| Variable | Default | Effect |
|---|---|---|
GATEGUARD_BASH_ROUTINE_DISABLED | unset (gate on) | Disables the routine-Bash gate only. The destructive-Bash gate (rm -rf, git reset --hard, drop table, dd if=, …) is unaffected. |
GATEGUARD_EXEMPT_GLOBS | unset (no exemptions) | Comma-separated globs; a matching Edit/Write/MultiEdit target skips first-touch fact-forcing. Intended for low-import-value trees (tests, generated artifacts, scratch dirs) where "who imports this / what schema" carries no signal. |
GATEGUARD_FACT_FORCE_FULL_DENIALS | 3 | How many denials emit the full four-fact block before later ones condense to a single line. 0 condenses from the very first denial. |
GATEGUARD_FACT_FORCE_MAX_DENIALS | unset (no cap) | Caps the total number of new-path Edit/Write/MultiEdit denials in a session. After the configured number of denials, new paths are allowed instead of denied; destructive Bash stays gated independently. The cap is best effort when hooks run concurrently: a lost count update can add a denial, but never lets a new path through early. Opt-in — unset, or any value that is not a whole non-negative integer, preserves the existing deny-every-new-path behaviour. Unlike GATEGUARD_FACT_FORCE_FULL_DENIALS, which only controls message detail, this changes whether the operation is blocked. |
GATEGUARD_BASH_EXTRA_DESTRUCTIVE | unset | Extra destructive-command patterns, as regex source, added to the built-in set. A malformed regex is treated as unset (built-ins still apply) and logged once to stderr. |
GATEGUARD_STATE_DIR | ~/.gateguard | Where per-session gate state is kept. If state cannot be persisted the gate allows the operation rather than looping, and names this variable in the warning. |
GATEGUARD_BASH_ROUTINE_DISABLED accepts 1, true, on, enabled,
enable, or yes (case- and whitespace-insensitive); any other value
leaves the gate on.
| Variable | Effect |
|---|---|
ECC_GATEGUARD=off | Disables GateGuard for the session. Accepts 0, false, off, disabled, or disable. |
GATEGUARD_DISABLED=1 | Same effect. Recognises 1 only — the spellings above do not apply here. |
For hook-level control, keep using ECC_DISABLED_HOOKS with the GateGuard hook ID.
GATEGUARD_EXEMPT_GLOBSPatterns match the entire project-relative target path. The project root is
CLAUDE_PROJECT_DIR, falling back to the hook payload's cwd, then the hook
process working directory. Relative globs never exempt targets outside that
root. Explicit absolute globs match the entire absolute target path and may
deliberately exempt paths outside the project.
Both patterns and paths use / separators and lowercase matching. * matches
within a segment, ** across segments, and ? one non-separator character.
**/ includes zero directories, so **/tests/** also matches tests/foo.js.
Malformed patterns are dropped without granting an exemption.
Since 2.2.1, services/** only covers the project's root services tree, and
*.md only covers its root Markdown files. Use **/*.md for all Markdown
files within the project. Existing unanchored exemptions may need adjustment:
{
"env": {
"GATEGUARD_BASH_ROUTINE_DISABLED": "1",
"GATEGUARD_EXEMPT_GLOBS": "**/tests/**,tests/**,**/*.test.*,**/docs/**,**/dist/**"
}
}pip install gateguard-ai
gateguard initThis adds .gateguard.yml for per-project configuration (custom messages, ignore paths, gate toggles).
%Y/%m/%d %H:%M. Checking data structure (with redacted values) prevents this entire class of bugs..gateguard.yml to ignore paths like .venv/, node_modules/, .git/.safety-guard — Runtime safety checks (complementary, not overlapping)code-reviewer — Post-edit review (GateGuard is pre-edit investigation)© affaan-m, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in skills/gateguard of affaan-m/ECC.
Open the folder on GitHubat commit 4eb71d9
Gateguard next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Gateguard this skillaffaan-m/ECC | 276k | — | ~2.5k | Automated safety check: Pass | MIT | |
| Hook Development for Claude Code Pluginsanthropics/claude-plugins-official | 38k | 10 repos | ~4.1k | Automated safety check: Notes | Apache-2.0 | |
| Plugin Settings Patternanthropics/claude-plugins-official | 38k | 7 repos | ~3k | Automated safety check: Pass | Apache-2.0 | |
| E2Ecallstack/react-native-pager-view | 3.4k | 3 repos | ~2.1k | Automated safety check: Pass | MIT | |
| Mole Bug Patternstw93/Mole | 70k | — | ~2k | Automated safety check: Pass | GPL-3.0 | |
| Neat-Freak Knowledge CloseoutKKKKhazix/khazix-skills | 21k | — | ~1.9k | Automated safety check: Pass | MIT |
anthropics/claude-plugins-official
Explains how to write Claude Code plugin hooks, both prompt-based checks and bash commands, for events such as PreToolUse, Stop and SessionStart.
anthropics/claude-plugins-official
Shows how Claude Code plugins keep per-project settings and state in .claude/plugin-name.local.md files with YAML frontmatter and a markdown body.
callstack/react-native-pager-view
Agentic end-to-end tests with e2e, the e2e runner. An agent skill from callstack/react-native-pager-view.
tw93/Mole
A catalog of recurring bug shapes in the Mole Mac cleaner, used to review safety-sensitive diffs for deletion safety, unbounded commands, shell traps and weak tests.
KKKKhazix/khazix-skills
Brings project docs, agent rule files, authorized memory and leftover workspace files back in line with what the code and runtime actually do at the end of a work session.
automazeio/ccpm
Runs a spec-driven workflow from PRD to epic to GitHub issues to parallel agents, with status, standup and blocked-work reports from bundled scripts.
affaan-m/ECC
Audits your installed Claude skills and commands for quality, with a quick mode for recently changed skills and a full mode that evaluates all of them through subagents.
affaan-m/ECC
Ingests, indexes, searches, edits and monitors video, audio and live streams through the VideoDB Python SDK, returning stream links, clips and timestamps.
affaan-m/ECC
Route broad documentation-governance requests to existing ECC skills and run an opt-in, read-only audit of mapped documentation roles, links, ADR indexes, and evidence references.
affaan-m/ECC
Scans installed skills for principles that recur across them and proposes rule-file changes: append, revise, add a section, create a file or leave as covered.
affaan-m/ECC
Builds DRAFT counterparty agreements from one markdown template and a small JSON spec per party, with clauses picked by the party's role.
affaan-m/ECC
Set an ECC-specific frontend design direction for production UI work.
Works with
PreToolUse fact-forcing gate that denies the first Edit/Write/Bash (including MultiEdit) attempt until the agent presents concrete facts (importers, data schemas, verbatim user instruction), then…. Gateguard is an agent skill from affaan-m/ECC.25 quality points.
Gateguard fits situations like: configuring the GateGuard hook; exempting paths via env vars; handling first-touch denials.
Run `npx skills add affaan-m/ECC --skill gateguard -a claude-code`. Or copy the skill folder (skills/gateguard in affaan-m/ECC) into .claude/skills/gateguard in your project. Claude Code loads it when a task matches its description.
Run `npx skills add affaan-m/ECC --skill gateguard -a codex`. Or copy the skill folder (skills/gateguard in affaan-m/ECC) into .agents/skills/gateguard in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add affaan-m/ECC --skill gateguard -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/gateguard, .gemini/skills/gateguard, .github/skills/gateguard and .opencode/skills/gateguard in your project.
Going by SKILL.md and its folder, Gateguard needs the command-line tools its instructions call (git and pip). Our summary lists: Python 3.
SKILL.md contains no URLs. Its commands use git and pip, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Gateguard is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.5k tokens (SKILL.md is roughly 9.9k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Gateguard: Hook Development for Claude Code Plugins (anthropics/claude-plugins-official, 38k stars), Plugin Settings Pattern (anthropics/claude-plugins-official, 38k stars), E2E (callstack/react-native-pager-view, 3.4k stars) and Mole Bug Patterns (tw93/Mole, 70k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
affaan-m (a GitHub user) maintains it in affaan-m/ECC, which has 276,111 GitHub stars. The repository holds 683 skills in this directory. The repository was last updated on October 10, 2026.
Source: affaan-m/ECC on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.