Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .claude/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
Type 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.
skills CLI
$ npx skills add coleam00/skills --skill hooks-create -a codex
Project install goes to .agents/skills/; add -g for ~/.codex/skills/.
Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .agents/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
skills CLI
$ npx skills add coleam00/skills --skill hooks-create -a cursor
Project install goes to .agents/skills/; add -g for ~/.cursor/skills/.
Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .cursor/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
skills CLI
$ npx skills add coleam00/skills --skill hooks-create -a gemini-cli
Project install goes to .agents/skills/; add -g for ~/.gemini/skills/.
Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .gemini/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
GitHub CLI
$ gh skill install coleam00/skills hooks-create
Installs 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).
skills CLI
$ npx skills add coleam00/skills --skill hooks-create -a github-copilot
Project install goes to .agents/skills/; add -g for ~/.copilot/skills/.
Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .github/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
skills CLI
$ npx skills add coleam00/skills --skill hooks-create -a opencode
OpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
Install the "hooks-create" agent skill from https://github.com/coleam00/skills/tree/main/.claude/skills/hooks-create into .opencode/skills/hooks-create/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "hooks-create", 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.
Facts
Skill name
hooks-create
GitHub stars
670
Token cost
~3.6k tokens
SKILL.md length
1,930 words
Files
1
Skills in repo
34
Repo updated
First seen
Licence
MIT
At a glance
Author a working Claude Code hook from a plain-English description of what it should guarantee or do.
Works in 6 steps: Understand the idea (start from… → Read the docs → Pick the event (and matcher) → …
You want a deterministic guarantee
SKILL.md covers What a hook is (30-second intro), The one thing to get right:…, Required reading (do this first) and The execution protocol (how a…, plus 3 more sections
Calls uv
What it does
Hooks Create is an agent skill from coleam00/skills. Author a working Claude Code hook from a plain-English description of what it should guarantee or do. You describe the behavior ("never let the agent edit my migrations", "don't stop until the tests pass", "log every command"); this skill picks the right lifecycle event, writes the hook script, and wires it into .claude/settings.json. Use when you want a deterministic guarantee or automation in your AI Layer and don't want to write the hook by hand. The meta-tool for the hooks primitive.
Its SKILL.md is about 3.6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Agent Workflows, covering Hooks and plugins and Plain language and style rules. The repository describes itself as: The agent skills I actually use to build software with coding agents. The PIV loop, planning, worktrees, and the meta-skills for building your own AI Layer. The licence is MIT.
When your agent uses it
You want a deterministic guarantee
Automation in your AI Layer and dont want to write the hook by hand
Example prompts
“never let the agent edit my migrations”
“t stop until the tests pass”
“log every command”
“/hooks-create”
Requirements
Python 3
Workflow steps
6 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 847be08. It shows what the files ask for, not the result of running them.
Tool permissions
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.
Runs code
Shell commands in SKILL.md call:
uv
From the folder's file list and the shell code blocks in SKILL.md.
Network
Links to these hosts (documentation or services it may open):
code.claude.com
From URLs in SKILL.md, links to its own repository left out.
Credentials
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Context cost
Hooks Create loads about 3.6k tokens when it runs. Until then it costs about 126 tokens; SKILL.md has 1,930 words of instructions outside code blocks.
Always· name and description, kept in context so the agent knows when to use it
~126
When it runs· the whole SKILL.md, loaded when a task matches
~3.6k
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.
Safety
Auto-check: notes
The automated check noted patterns worth knowing about, such as sudo or a known installer.
NoteMentions a .env fileSKILL.md:23
idea** ("the agent should never read my `.env`"); this skill writes the **code** and wires
NoteMentions a .env fileSKILL.md:82
*How precisely** should it match? ("any `.env` file", "the `migrations/` folder", "`rm -rf`", "my test
NoteMentions a .env fileSKILL.md:217
t with the user about the edges (e.g. a `.env` matcher won't catch a base64'd read).
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.
Download SKILL.mdSave it as .claude/skills/hooks-create/SKILL.md (or your agent's skills folder).
name
hooks-create
description
Author a working Claude Code hook from a plain-English description of what it should guarantee or do. You describe the behavior ("never let the agent edit my migrations", "don't stop until the tests pass", "log every command"); this skill picks the right lifecycle event, writes the hook script, and wires it into .claude/settings.json. Use when you want a deterministic guarantee or automation in your AI Layer and don't want to write the hook by hand. The meta-tool for the hooks primitive.
argument-hint
what-the-hook-should-do
Create Hook: Turn an Idea Into a Working Claude Code Hook
What the user wants the hook to do: $ARGUMENTS
If that is filled in, treat it as the behavior spec and start from it. Don't re-ask what they already told you;
only ask to pin down the gaps (the exact paths / commands / patterns, and whether it must block). If it is
blank, start by asking what the hook should guarantee or do (Workflow step 1).
What a hook is (30-second intro)
A hook is deterministic code that fires automatically on a Claude Code lifecycle event - before a tool
runs, after it runs, when the agent tries to finish, when a session starts, and so on. Unlike a skill or a
subagent, the agent does not choose to invoke a hook - it fires whether the model "remembers" or not. That is
the whole point: a rule asks the agent to behave; a hook guarantees it, at the tooling layer the model
can't talk its way around.
The user brings the idea ("the agent should never read my .env"); this skill writes the code and wires
it in. They don't need to know Python.
It's all composition - a hook is just a small script the harness runs at a defined moment, configured in
.claude/settings.json. You're adding one more deterministic guarantee to the AI Layer.
The one thing to get right: which event, and can it block?
The behavior the user wants maps to one lifecycle event. Pick by when it should fire and whether it must
stop something:
The user wants to…
Event
Can it block?
Stop the agent from doing something (read a secret, edit a protected path, run a destructive command)
PreToolUse ⭐
Yes - block the tool before it runs
React after an action (auto-format an edited file, log a command, inject context)
PostToolUse
No - the tool already ran; observe / format / inject only
Guarantee work isn't "done" until a check passes (don't stop until tests/lint/types are green)
Stop (or SubagentStop)
Yes - block the stop and send the agent back to work
Gate or scan the user's prompt before the model sees it
UserPromptSubmit
Yes - block the prompt; can also inject context
Load context every time a session starts
SessionStart
No - inject context only
Get notified when the agent needs you / finishes
Notification (or Stop)
No - side-effect only (desktop/Slack/sound)
Snapshot state before context compaction
PreCompact
No
Pre = guarantee/gate. Post = react/log. If the user's goal is "make sure X never happens" or "don't finish
until Y," it's a blocking hook (PreToolUse / Stop / UserPromptSubmit). If it's "do Z when W happens," it's an
observe/react hook (PostToolUse / SessionStart / Notification).
Required reading (do this first)
The hook event list and the exact stdin/stdout contract evolve - don't rely on a snapshot. Before writing,
fetch the current docs and confirm the event name, its input fields, and its control protocol:
Use WebFetch on these and verify against what you're about to write. If the fetch fails, proceed from the
canonical events in the table above and say so in your report so the user can double-check.
The execution protocol (how a hook talks to Claude Code)
Input: Claude Code passes a JSON object on stdin - always includes session_id, cwd,
hook_event_name; event-specific fields like tool_name + tool_input (tool events), prompt
(UserPromptSubmit), source (SessionStart).
Output / control:
exit 0 - allow / success. For UserPromptSubmit and SessionStart, anything printed to stdout is
injected into the agent's context.
exit 2 - block. The action is prevented and whatever you print to stderr is fed back to the
agent as the reason, so it adapts. (Only blocking-capable events honor this - see the table.)
any other exit code - non-blocking error; shown to the user, execution continues.
Advanced (optional): instead of exit codes, print a JSON object on stdout - e.g. {"decision":"block", "reason":"…"} (Stop), or {"hookSpecificOutput":{"hookEventName":"PreToolUse", "permissionDecision":"deny","permissionDecisionReason":"…"}}. Prefer the simple exit-code form unless the
user needs to modify input/output or inject context with additionalContext. Confirm field names against
the fetched docs.
Workflow
1. Understand the idea (start from $ARGUMENTS; ask only to fill gaps)
Start from what the user already described in $ARGUMENTS (the user may not be technical). Pin down two things in
plain language, asking only for what is missing:
What should happen or be prevented, and when (before/after an action, at finish, at session start)?
How precisely should it match? ("any .env file", "the migrations/ folder", "rm -rf", "my test
command exits non-zero"). Get the concrete file paths / commands / patterns - the guarantee is only as good as
what it matches, so don't guess. If the ask is vague, propose a concrete interpretation and confirm.
2. Read the docs
Fetch the hooks reference/guide (above) and confirm the target event's name, stdin fields, and control protocol.
3. Pick the event (and matcher)
Use the table to choose the single event. Choose a matcher that scopes it tightly - for tool events, the
tool name(s) (e.g. "Bash", "Edit|Write", "mcp__.*"); empty/"*" means every occurrence. Don't fire on
everything if the goal is specific.
4. Write the hook script
Default to a uv single-file Python script at .claude/hooks/<event_snake_case>.py - a uv run --script
shebang plus inline # /// script metadata, so it needs no install and no project venv of its own. Use another
language only if the user asks.
Read the JSON from stdin, do the check, and:
to block: print a clear reason to stderr and sys.exit(2);
to allow: sys.exit(0) (optionally print context to stdout for the injecting events).
Fail open. Wrap the body so any unexpected error exits 0 (a broken hook must never brick the user's
session). The only intentional non-zero exit is the deliberate exit 2 block.
Keep it lean and readable - the user will want to tweak the matched paths/commands later.
If a hook already exists for that event, extend it rather than overwrite (add your check; keep theirs).
Stop / SubagentStop only: check stop_hook_active first and sys.exit(0) when it is true. Without
that guard the hook blocks the stop, the agent works, tries to stop again, is blocked again - a loop.
⚠️ Running a project command from a hook (read this before writing one)
The hook itself runs under uv run, in an isolated ephemeral environment. Its interpreter is NOT the
project's interpreter and does NOT have the project's dependencies. So:
NEVER rebuild the command with sys.executable or a bare ["python", "-m", "pytest", ...] list. That
runs the hook's throwaway python, which has no pytest, no project packages, nothing. The command fails with
No module named …every single time - so a "don't finish until tests pass" hook blocks on green as
readily as on red, and reports a nonsense reason. It looks like it works. It does not.
DO run the user's command verbatim, as a shell string, in the project directory - with uv's ephemeral
venv stripped AND the project's own venv put first. Both steps are required. shell=True alone is not
enough: uv run puts its throwaway interpreter first on PATH and sets VIRTUAL_ENV. But removing uv's
venv does not activate the project's - a hook is not the user's shell, so .venv was never on PATH to
begin with, and python falls through to whatever global interpreter the machine has. That global one has a
different (often broken) set of packages, so the hook exits 2 on a perfectly green suite and blames some
unrelated module. Copy this helper as-is:python
TEST_COMMAND = "python -m pytest -q" # exactly what the user typed; the one line they'll edit
def _project_env(project_root: Path) -> dict:
"""os.environ with uv's ephemeral venv removed and the PROJECT's venv first."""
env = os.environ.copy()
ephemeral = env.pop("VIRTUAL_ENV", None)
parts = env.get("PATH", "").split(os.pathsep)
if ephemeral: # 1. uv's throwaway venv, out
drop = {os.path.join(ephemeral, "Scripts"), os.path.join(ephemeral, "bin")}
parts = [p for p in parts if p not in drop]
for candidate in (".venv", "venv"): # 2. the project's own venv, first
for bindir in ("Scripts", "bin"):
venv_bin = project_root / candidate / bindir
if venv_bin.is_dir():
env["VIRTUAL_ENV"] = str(project_root / candidate)
parts.insert(0, str(venv_bin))
env["PATH"] = os.pathsep.join(parts)
return env
env["PATH"] = os.pathsep.join(parts)
return env
root = Path(hook_input["cwd"]) # the project root Claude Code passes in
result = subprocess.run(
TEST_COMMAND, shell=True, capture_output=True, text=True,
cwd=str(root), env=_project_env(root),
)
Put the command in a single named constant at the top of the file so the user can edit one obvious line.
If the command must run from a subdirectory (a monorepo, or a project whose test config lives deeper -
e.g. app/backend/), ask for that, and pass it: cwd=Path(hook_input["cwd"]) / "app/backend". Getting this
wrong produces a hook that always blocks, which the user will read as "hooks are broken."
Show full SKILL.md (531 more words)Show less
5. Wire it into settings.json
Edit .claude/settings.json (create it if absent). Merge into any existing hooks block - never clobber
other events or other hooks on the same event. Shape:
Run the hook before you hand it over. Feed it a sample event on stdin and check the exit code - do not ship a
hook you have only read. A hook that always blocks, or never blocks, looks identical to a working one until it
fires at the wrong moment.
bash
# should ALLOW (exit 0)
echo '{"session_id":"t","cwd":"<project-root>","hook_event_name":"Stop","stop_hook_active":false}' | uv run .claude/hooks/stop.py; echo "exit=$?"
For a command-running hook (tests/lint/types), this is mandatory and you must check both directions:
it exits 0 while the command passes, and exits 2 once it genuinely fails. If it exits 2 in both states, the
command is not resolving - re-read the warning in step 4 about sys.executable.
For a blocking guard, feed it one payload that should be blocked and one that should pass.
If a check comes back wrong, fix the script and re-run before reporting success.
Then:
Tell the user what you built, in plain words: which event, what it guarantees, and the one line they'd
change to adjust it.
Give them a way to prove it in the agent: for a blocking hook, an action that should be blocked ("ask me
to read the env file - watch it refuse"); for an observe hook, where the output lands (the log, the notification).
Report what you verified, and say plainly if you could not verify something.
Security note (always say this): a hook runs arbitrary code automatically, with your credentials, on every
matching event. Review hooks like you review CI config; only run hooks you trust. (Same caution as MCP
servers.)
Quality checks
✅ The behavior maps to the right event, and a blocking goal uses a blocking-capable event (PreToolUse /
Stop / UserPromptSubmit) - not PostToolUse.
✅ The matcher is scoped to what the user actually meant (not firing on everything by accident).
✅ The script fails open - any error exits 0; the only exit 2 is the intended block, with a clear stderr reason.
✅ Any project command runs verbatim via shell=True in the project cwd, with uv's ephemeral venv
stripped and the project's own venv put first on PATH - never rebuilt with sys.executable (the hook's
own interpreter has none of the project's dependencies, and the global one has the wrong ones).
✅ A Stop / SubagentStop hook honors stop_hook_active so it cannot loop.
✅ settings.json was merged, not overwritten; existing hooks still present.
✅ You ran the hook and confirmed it exits 0 when it should allow and 2 when it should block - not just read it.
✅ The user got a plain-English explanation + a test + the security note.
Notes
Hooks are the deterministic floor of the AI Layer - use them for the non-negotiables (secrets, protected paths,
"don't finish until green"), not for things a rule or skill handles well enough.
A blocking hook's coverage is only as good as its matcher - it guarantees the hook runs, but you decide
what it catches. Be honest with the user about the edges (e.g. a .env matcher won't catch a base64'd read).
Keep hooks fast - they run on the matched event every time. Heavy work belongs in an async hook or a skill.
Hooks Create 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.
Explains how to write agents for Claude Code plugins: the markdown file with YAML frontmatter, trigger descriptions, model and color settings, and system prompt design.
A guide to creating and managing Claude Code skills with auto-activation: skill-rules.json triggers, hooks, enforcement levels, YAML frontmatter and progressive disclosure.
Explains how to bundle Model Context Protocol servers in a Claude Code plugin, covering config files, stdio, SSE, HTTP and WebSocket server types, and authentication.
Explains how to write Claude Code slash commands: Markdown files with YAML frontmatter, arguments, file references, bash context and interactive prompts.
Measure whether a repository's AI instructions still earn their place, by running the same real task many times with the layer intact and with it stripped, then grading every rule against what…
Take a PRD and build a dark factory around it - a repository that takes work in as an issue and ships validated code out with nobody at the keyboard - one component at a time, into the user's actual…
Take real control of the desktop - list and focus windows, type, paste, click, scroll, and screenshot - on Windows, macOS or Linux, and drive other coding-agent sessions running in terminals.
Build a personal signal engine from scratch - a system that reads every source someone cares about each day (changelogs and release notes, communities, feeds, videos, papers), makes a quick decision…
Create one or more git worktrees for parallel development, each on its own branch with gitignored config copied in, dependencies installed, and a health check, by fanning out a setup subagent per…
Author a working Claude Code hook from a plain-English description of what it should guarantee or do. Hooks Create is an agent skill from coleam00/skills. Author a working Claude Code hook from a plain-English description of what it should guarantee or do.
When should I use Hooks Create?
Hooks Create fits situations like: you want a deterministic guarantee; automation in your AI Layer and dont want to write the hook by hand.
How do I install Hooks Create in Claude Code?
Run `npx skills add coleam00/skills --skill hooks-create -a claude-code`. Or copy the skill folder (.claude/skills/hooks-create in coleam00/skills) into .claude/skills/hooks-create in your project. Claude Code loads it when a task matches its description.
How do I install Hooks Create in Codex?
Run `npx skills add coleam00/skills --skill hooks-create -a codex`. Or copy the skill folder (.claude/skills/hooks-create in coleam00/skills) into .agents/skills/hooks-create in your project. Codex loads it when a task matches its description.
Can I use Hooks Create in Cursor, Gemini CLI or GitHub Copilot?
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add coleam00/skills --skill hooks-create -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/hooks-create, .gemini/skills/hooks-create, .github/skills/hooks-create and .opencode/skills/hooks-create in your project.
What does Hooks Create need to run?
Going by SKILL.md and its folder, Hooks Create needs the command-line tools its instructions call (uv). Our summary lists: Python 3.
Does Hooks Create access the network?
SKILL.md names 1 domain. As links in the text: code.claude.com. This is read from the text; nothing was executed.
Is Hooks Create safe to install?
Our automated static check of SKILL.md found notes only (mentions a .env file), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
What licence does Hooks Create use?
Hooks Create is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
How many tokens does Hooks Create use?
About 3.6k tokens (SKILL.md is roughly 14k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
What are the alternatives to Hooks Create?
Skills that share tags, products or a category with Hooks Create: Hook Development for Claude Code Plugins (anthropics/claude-plugins-official, 38k stars), Claude Code Agent Development (anthropics/claude-plugins-official, 38k stars), Claude Code Skill Developer Guide (diet103/claude-code-infrastructure-showcase, 10k stars) and Plugin Settings Pattern (anthropics/claude-plugins-official, 38k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Who maintains Hooks Create?
coleam00 (a GitHub user) maintains it in coleam00/skills, which has 670 GitHub stars. The repository holds 34 skills in this directory. The repository was last updated on October 7, 2026.
Source: coleam00/skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.