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.
> /plugin marketplace add aaron-he-zhu/aaron-marketing-skills > /plugin install aaron-marketing@aaron
Ships with aaron-marketing. Installing the plugin gets these hooks.
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.
- Matches
startup|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
- Matches
Write|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash
PostToolUse
- Matches
Write|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash
PostToolUseFailure
- Matches
Write|Edit|NotebookEdit|Bash|PowerShell|Monitor|mcp__.*bash
PostToolBatch
bash
Stop
bash
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.
120 marketing skills, 7 disciplines, one contract — your AI marketing staff, installable as a plugin, portable skills, or an 8-bot team.

