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
2.8k8 commands7 hooks
Install
> /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.

  • 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.

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.

Get the whole plugin
Stats
2,796
Stars
361
Forks
Active
Maintenance
Python
Language
Apache-2.0
License
1h ago
Last commit
9mo ago
Created

Repo: aaron-he-zhu/aaron-marketing-skills