Skip to content
Marketing
Hook

Hooks

What aaron-marketing runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.

From plugin
aaron-marketing
3.1k8 commands7 hooks

Claude Code

> /plugin marketplace add aaron-he-zhu/aaron-marketing-skills
> /plugin install aaron-marketing@aaron

What fires, and when

SessionStart

Fires once when a session begins, and again after a context compaction. It is where a plugin sets up its environment, or restores state the compaction dropped.

  • Matchesstartup|resume|clear|compactbash

UserPromptSubmit

Fires before Claude sees each prompt you send. A plugin can use it to inject context, so the same instruction reaches the model every turn instead of only at session start.

  • bash

PreToolUse

  • MatchesWrite|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash

PostToolUse

  • MatchesWrite|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash

PostToolUseFailure

  • MatchesWrite|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash

PostToolBatch

  • bash

Stop

  • bash
Read hooks/hooks.json

Where it lives

  • hooks/claude-hook.shGitHub
    Read the script
    #!/usr/bin/env bash
    set -u
    export LC_ALL=C
    m="${1:-}"
    MAX_HOOK_INPUT_BYTES=4000000
    HOT_CONTEXT_BYTES=9000
    CHECKPOINT_CONTEXT_BYTES=3000
    RUN_CONTEXT_BYTES=3072
    in="$(head -c $((MAX_HOOK_INPUT_BYTES+1)) 2>/dev/null || true)"
    
    esc(){ LC_ALL=C tr -d '\000-\010\013\014\016-\037'|awk 'BEGIN{ORS=""}{gsub(/\\/,"\\\\");gsub(/"/,"\\\"");gsub(/\t/,"\\t");gsub(/\r/,"\\r");if(NR>1)printf "\\n";printf "%s",$0}'; }
    ctx(){ [ -n "$2" ] || exit 0; b="$2"; [ "${#b}" -gt 24000 ]&&b="${b:0:24000}...[truncated]"; e="$(printf "%s" "$b"|esc)"; printf '{"hookSpecificOutput":{"hookEventName":"%s","additionalContext":"%s"}}\n' "$1" "$e"; }
    block(){ r="$(printf "%s" "$1"|esc)"; printf '{"decision":"block","reason":"%s"}\n' "$r"; exit 0; }
    deny(){ r="$(printf "%s" "$1"|esc)"; printf '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"%s"}}\n' "$r"; exit 0; }
    if [ "${#in}" -gt "$MAX_HOOK_INPUT_BYTES" ]; then
      case "$m" in pre-tool-use) deny "Hook input exceeds the bounded validation limit.";; post-tool-use|post-tool-failure|post-tool-batch|stop) block "Hook input exceeds the bounded validation limit.";; *) exit 0;; esac
    fi
    jg(){ if command -v jq >/dev/null 2>&1; then printf "%s" "$in"|jq -r "$1 // empty" 2>/dev/null; elif command -v python3 >/dev/null 2>&1; then printf "%s" "$in"|python3 -c 'import sys,json
    try:
     d=json.load(sys.stdin)
    except Exception:
     sys.exit(0)
    for k in sys.argv[1].lstrip(".").replace("?","").split("."):
     if isinstance(d,dict) and k in d: d=d[k]
     else: sys.exit(0)
    if isinstance(d,str): print(d)
    elif isinstance(d,bool): print(str(d).lower())
    elif isinstance(d,(int,float)): print(d)' "$1"; else k="$(printf "%s" "$1"|sed 's/.*\.//;s/[? ].*//')"; v="$(printf "%s" "$in"|tr '\n' ' '|grep -o "\"$k\"[[:space:]]*:[[:space:]]*\"[^\"]*\""|head -1|sed "s/^\"$k\"[[:space:]]*:[[:space:]]*\"\(.*\)\"$/\1/")"; [ -n "$v" ] || v="$(printf "%s" "$in"|tr '\n' ' '|grep -oE "\"$k\"[[:space:]]*:[[:space:]]*(true|false|-?[0-9][0-9.]*)"|head -1|sed -E "s/^\"$k\"[[:space:]]*:[[:space:]]*//")"; printf "%s\n" "$v"; fi; }
    root(){ r="${CLAUDE_PROJECT_DIR:-}"; [ -n "$r" ] || r="$(jg '.cwd')"; [ -n "$r" ] || r="$(pwd)"; (cd "$r" 2>/dev/null && pwd -P) || return 1; }
    sf(){ rt="$1"; raw="$2"; [ -n "$raw" ] || return 1; case "$raw" in /*) p="$raw";; *) p="$rt/$raw";; esac; d="$(dirname "$p")"; b="$(basename "$p")"; ad="$(cd "$d" 2>/dev/null && pwd -P)" || return 1; a="$ad/$b"; [ ! -L "$a" ] || return 1; case "$a" in "$rt"/*) printf "%s\n" "$a";; *) return 1;; esac; }
    bf(){ base="$1"; rel="$2"; [ ! -L "$base" ]||return 1; p="$base"; IFS=/ read -r -a parts <<< "$rel"; for part in "${parts[@]}"; do [ -n "$part" ]&&[ "$part" != "." ]&&[ "$part" != ".." ]||return 1; p="$p/$part"; [ ! -L "$p" ]||return 1; done; d="$(dirname "$p")"; bd="$(cd "$base" 2>/dev/null&&pwd -P)"||return 1; ad="$(cd "$d" 2>/dev/null&&pwd -P)"||return 1; a="$ad/$(basename "$p")"; case "$a" in "$bd"/*) printf "%s\n" "$a";; *) return 1;; esac; }
    mf(){ rt="$1"; [ ! -L "$rt/memory" ]||return 1; bf "$rt/memory" "$2"; }
    sr(){ LC_ALL=C tr -d '\000-\010\013\014\016-\037' < "$1" 2>/dev/null|awk -v n="$2" 'NR>n{exit}{x=$0;l=tolower(x);if(l~/(^|[^a-z])(system|developer|assistant):|ignore (previous|all previous)|disregard previous instructions|follow these instructions|treat this as.*system|you are chatgpt|reveal (the |your )?(secret|system prompt)|<\/?system>|<\/?developer>|<\/?assistant>|tooluse|tool_use)/)x="[redacted directive-like project record line]";if(l~/^project:[[:space:]]*(\/|\.\.)/)x="project: [redacted invalid project scope]";if(length(x)>500)x=substr(x,1,500)"...";print x}'|head -c "$3"; }
    tjd(){ date +%Y-%m-%d 2>/dev/null|awk -F- 'NF==3{a=int((14-$2)/12);yy=$1+4800-a;mm=$2+12*a-3;print $3+int((153*mm+2)/5)+365*yy+int(yy/4)-int(yy/100)+int(yy/400)-32045}'; }
    sod(){ awk -v t="$2" -v thr="$3" 'function j(y,m,d, a,yy,mm){a=int((14-m)/12);yy=y+4800-a;mm=m+12*a-3;return d+int((153*mm+2)/5)+365*yy+int(yy/4)-int(yy/100)+int(yy/400)-32045} {s=$0;while(match(s,/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/)){dd=substr(s,RSTART,10);s=substr(s,RSTART+RLENGTH);split(dd,p,"-");if(p[2]>=1&&p[2]<=12&&p[3]>=1&&p[3]<=31){v=j(p[1],p[2],p[3]);if(mn==""||v<mn){mn=v;md=dd}}}} END{if(mn!=""){a=t-mn;if(a>thr)print md" "a}}' "$1"; }
    vaf(){ rt="$1"; f="$2"; rel="${f#"$rt"/}"; [ -f "$f" ] || return 0; [ ! -L "$f" ] || block "Artifact Gate failure in $rel: symlinked artifacts are not allowed."; pr="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." 2>/dev/null && pwd -P)}"; av="$pr/scripts/validate-audit-artifact.py"; [ -f "$av" ] || block "Artifact Gate failure in $rel: validator unavailable at $av."; ve="$(python3 "$av" "$f" --relative-path "$rel" 2>&1)" || block "Artifact Gate failure in $rel. The v3 audit contract is fail-closed: $ve"; }
    saa(){ rt="$1"; rawbase="$rt/memory/audits"; [ -e "$rawbase" ] || return 0; base="$(mf "$rt" "audits" || true)"; [ -n "$base" ] && [ -d "$base" ] || block "Artifact Gate failure: memory/audits must be a real directory inside the project."; pr="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." 2>/dev/null && pwd -P)}"; av="$pr/scripts/validate-audit-artifact.py"; [ -f "$av" ] || block "Artifact Gate failure: validator unavailable at $av."; ve="$(python3 "$av" --scan-root "$base" 2>&1)" || block "Artifact Gate reserved-sink sweep failed: $ve"; }
    pmp(){ rt="$1"; pr="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." 2>/dev/null && pwd -P)}"; pv="$pr/scripts/check-memory-private.py"; [ -f "$pv" ] || deny "Memory privacy preflight unavailable at $pv; refusing an unverified write-capable tool call."; if ! command -v python3 >/dev/null 2>&1; then case "$in" in *[mM][eE][mM][oO][rR][yY][/\\]*|*[/\\][mM][eE][mM][oO][rR][yY]*) deny "python3 is required to verify memory-namespace operations; install python3 or avoid memory/ paths.";; *) return 0;; esac; fi; pe="$(printf "%s" "$in" | python3 "$pv" --root "$rt" --hook-input 2>&1)" || deny "$pe"; }
    paw(){ rt="$1"; pr="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." 2

Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.

@aaron-he-zhu
Ships withaaron-marketing

120 marketing skills, 7 disciplines, one contract — your AI marketing staff, installable as a plugin, portable skills, or an 8-bot team.

Stars on GitHub

Momentum

stars in total
3.1k
Star history of aaron-he-zhu/aaron-marketing-skills on GitHub, a chart by star-history.com

More plugins that ship hooks.

claude-seo

claude-seo

An open-source SEO analysis plugin for Claude Code covering technical SEO, content quality, Schema.org markup, AI search optimization, local SEO and e-commerce, with specialist skills for keyword data, backlinks, image generation and site crawling.

33 skills+229k
@agricidaniel@agricidaniel
Install Plugin
digital-marketing-pro

digital-marketing-pro

Runs a consistent marketing strategy process across every brand in a portfolio, producing the same planning files in the same order so agencies and in-house teams can audit depth and catch compliance gaps. Covers SEO audits, ad copy, A/B test planning and AI search visibility.

164 skills+3952
@indranilbanerjee@indranilbanerjee
Install Plugin
ralph-wiggum-marketer

ralph-wiggum-marketer

Runs an autonomous loop for SaaS content marketing and copywriting, with commands to initialize, run, check status, and cancel it. A stop hook keeps the loop going when an agent stops.

1 skill+2780
@muratcankoylan@muratcankoylan
Install Plugin
claude-repurpose

claude-repurpose

Content Repurposing Engine for Claude Code, Turn 1 piece of content into 10+ platform-optimized posts in seconds.

21 skills+2175
@agricidaniel@agricidaniel
Install Plugin
content-ideas

content-ideas

Scrapes tracked competitor accounts on X, Instagram, TikTok and YouTube, scores what is performing well, and turns it into a daily feed of content ideas framed against your own brand.

1 skill+2156
@bradautomates@bradautomates
Install Plugin
email

email

Professional email management, deliverability optimization, and marketing strategy powered by Claude Code.

6 skills+2138
@agricidaniel@agricidaniel
Install Plugin
claude-seo-ai

claude-seo-ai

The SEO + AI-search (GEO/AEO) optimization toolkit for Claude Code, two-score audit + opt-in fixer. Built for 2026-2027.

34 skills+287
@hainrixz@hainrixz
Install Plugin
akii-seo-ai-search-optimizer

akii-seo-ai-search-opt…

A free Claude Code toolkit for SEO, AI answer engine optimization, and generative engine optimization. Its skills cover AI visibility checks, broken link audits, competitor scorecards, content briefs, and content strategy plans.

12 skills+380
@akii-technologies-ltd@akii-technologies-ltd
Install Plugin

Questions about the hooks in aaron-marketing.

Which coding agents can use the hooks in aaron-marketing?
The hooks in aaron-marketing install in Claude Code and Cursor: each runs Claude Code hooks from .claude/settings.json, so copy the hooks there.