Skip to content
FrankX.AI
AI ArchitectureJan 27, 20268 min read1,559 words

The ACOS Hooks System: Automated Quality Gates

TL;DR

Master ACOS hooks for automated quality enforcement. SessionStart, PreToolUse, PostToolUse, and Notification hooks that catch issues before they ship.

Frank Riemer
FrankX
AI Architect & Independent Creator
Ex-Oracle AI Architect ยท Starlight & ACOS Systems
Master ACOS hooks for automated quality enforcement. SessionStart, PreToolUse, PostToolUse, and Notification hooks that catch issues before they ship.
Reading Goal

Implement hooks that automatically enforce quality standards in your ACOS workflows.

The ACOS Hooks System: Automated Quality Gates

Catch mistakes before they ship. Automatically.

TL;DR

ACOS hooks are automated checkpoints that run at key moments: SessionStart (load context), PreToolUse (check before writing), PostToolUse (validate after writing), and Notification (suggest skills). Configure them in .claude/hooks.json. This guide covers the 4 hook types, practical examples, and how to build custom quality gates.

What Are ACOS Hooks?

Hooks are automated scripts that run at specific points in the Claude Code lifecycle. Think of them as quality gates that catch issues before they become problems.

Without Hooks:

User: "Write a blog post"
Claude: [Writes post with banned phrases]
User: [Publishes, realizes brand voice is wrong]
User: [Manually fixes, wastes time]

With Hooks:

User: "Write a blog post"
Claude: [Writes post]
Hook: [Detects "synergy", suggests alternative]
Claude: [Rewrites with correct voice]
User: [Publishes confidently]

The 4 Hook Categories

1. SessionStart Hooks

When: Every time you open Claude Code Purpose: Load context, set up environment

{
  "hooks": {
    "SessionStart": [
      {
        "name": "load-acos-context",
        "script": "echo 'ACOS v6.0 loaded'",
        "timeout": 5000
      },
      {
        "name": "check-skill-rules",
        "script": "cat ~/.claude/skill-rules.json > /dev/null && echo 'Skills ready'"
      }
    ]
  }
}

Use Cases:

  • Load project-specific context
  • Verify environment setup
  • Display system status
  • Pre-load frequently used skills

2. PreToolUse Hooks

When: Before Claude writes to a file or executes a tool Purpose: Validate content before it's created

{
  "hooks": {
    "PreToolUse": [
      {
        "name": "brand-voice-check",
        "trigger": "Write|Edit",
        "script": "check-brand-voice.sh",
        "block_on_failure": true
      }
    ]
  }
}

Use Cases:

  • Brand voice enforcement
  • Security scanning
  • Style guide compliance
  • Banned phrase detection

3. PostToolUse Hooks

When: After Claude completes a tool action Purpose: Validate output, trigger follow-up actions

{
  "hooks": {
    "PostToolUse": [
      {
        "name": "quality-score",
        "trigger": "Write",
        "script": "calculate-quality-score.sh"
      },
      {
        "name": "auto-format",
        "trigger": "Write|Edit",
        "script": "prettier --write"
      }
    ]
  }
}

Use Cases:

  • Auto-formatting
  • Quality scoring
  • Test running
  • Lint checking

4. Notification Hooks

When: When specific patterns are detected in conversation Purpose: Suggest relevant skills or actions

{
  "hooks": {
    "Notification": [
      {
        "name": "suggest-skill",
        "pattern": "test|testing|spec",
        "message": "Consider loading test-driven-development skill"
      }
    ]
  }
}

Use Cases:

  • Skill suggestions
  • Best practice reminders
  • Context-aware tips

Configuring hooks.json

The hooks configuration lives in .claude/hooks.json:

{
  "version": "1.0",
  "hooks": {
    "SessionStart": [...],
    "PreToolUse": [...],
    "PostToolUse": [...],
    "Notification": [...]
  },
  "enforcement": {
    "bannedPhrases": ["synergy", "leverage", "circle back"],
    "requiredPatterns": ["TL;DR", "FAQ"]
  }
}

Hook Properties

PropertyTypeDescription
namestringUnique identifier
scriptstringShell command to run
triggerstringTool name pattern (regex)
patternstringText pattern to match
timeoutnumberMax execution time (ms)
block_on_failurebooleanStop if hook fails
messagestringNotification message

Practical Examples

Example 1: Brand Voice Enforcement

Catch phrases that don't match your brand:

{
  "hooks": {
    "PreToolUse": [
      {
        "name": "brand-voice",
        "trigger": "Write|Edit",
        "script": "~/.claude/scripts/brand-voice-check.sh",
        "block_on_failure": true
      }
    ]
  },
  "enforcement": {
    "bannedPhrases": [
      "synergy",
      "leverage",
      "circle back",
      "touch base",
      "boil the ocean",
      "low-hanging fruit",
      "move the needle",
      "think outside the box"
    ],
    "suggestedAlternatives": {
      "synergy": "collaboration",
      "leverage": "use",
      "circle back": "follow up",
      "touch base": "connect",
      "boil the ocean": "try to do everything at once"
    }
  }
}

brand-voice-check.sh:

#!/bin/bash
content="$1"
banned=("synergy" "leverage" "circle back")

for phrase in "${banned[@]}"; do
  if echo "$content" | grep -qi "$phrase"; then
    echo "BLOCKED: Found banned phrase '$phrase'"
    echo "Suggestion: Use alternative from brand guide"
    exit 1
  fi
done

echo "Brand voice check passed"
exit 0

Example 2: SEO Validation

Ensure articles meet SEO requirements:

{
  "hooks": {
    "PostToolUse": [
      {
        "name": "seo-check",
        "trigger": "Write",
        "pattern": "\\.mdx$",
        "script": "~/.claude/scripts/seo-check.sh"
      }
    ]
  }
}

seo-check.sh:

#!/bin/bash
file="$1"

# Check for TL;DR
if ! grep -q "## TL;DR\|## TL;DR" "$file"; then
  echo "WARNING: Missing TL;DR section"
fi

# Check for FAQ
if ! grep -q "## FAQ\|## Frequently Asked" "$file"; then
  echo "WARNING: Missing FAQ section"
fi

# Check meta description length
desc=$(grep -A1 "description:" "$file" | tail -1 | tr -d '"')
len=${#desc}
if [ $len -lt 150 ] || [ $len -gt 160 ]; then
  echo "WARNING: Meta description is $len chars (target: 150-160)"
fi

echo "SEO check complete"

Example 3: Auto-Formatting

Format code after every write:

{
  "hooks": {
    "PostToolUse": [
      {
        "name": "prettier",
        "trigger": "Write|Edit",
        "pattern": "\\.(ts|tsx|js|jsx|json)$",
        "script": "prettier --write"
      },
      {
        "name": "eslint-fix",
        "trigger": "Write|Edit",
        "pattern": "\\.(ts|tsx|js|jsx)$",
        "script": "eslint --fix"
      }
    ]
  }
}

Example 4: Test Running

Run tests after code changes:

{
  "hooks": {
    "PostToolUse": [
      {
        "name": "run-tests",
        "trigger": "Write|Edit",
        "pattern": "src/.*\\.(ts|tsx)$",
        "script": "npm test -- --related",
        "timeout": 30000
      }
    ]
  }
}

Example 5: Skill Suggestions

Suggest skills based on context:

{
  "hooks": {
    "Notification": [
      {
        "name": "suggest-tdd",
        "pattern": "test|testing|spec|coverage",
        "message": "๐Ÿ’ก Consider using: /skill test-driven-development"
      },
      {
        "name": "suggest-security",
        "pattern": "auth|password|token|secret",
        "message": "๐Ÿ”’ Security patterns: /skill security-best-practices"
      },
      {
        "name": "suggest-music",
        "pattern": "suno|track|song|music",
        "message": "๐ŸŽต Music creation: /skill suno-ai-mastery"
      }
    ]
  }
}

Building Custom Hooks

Step 1: Create the Script

mkdir -p ~/.claude/scripts
touch ~/.claude/scripts/my-hook.sh
chmod +x ~/.claude/scripts/my-hook.sh

Step 2: Write the Logic

#!/bin/bash
# my-hook.sh

# Input: file path or content passed as argument
input="$1"

# Your validation logic
if [[ condition ]]; then
  echo "Check passed"
  exit 0
else
  echo "Check failed: reason"
  exit 1
fi

Step 3: Register in hooks.json

{
  "hooks": {
    "PreToolUse": [
      {
        "name": "my-custom-hook",
        "trigger": "Write",
        "script": "~/.claude/scripts/my-hook.sh",
        "block_on_failure": true
      }
    ]
  }
}

Step 4: Test

# Test the script directly
~/.claude/scripts/my-hook.sh "test content"

# Then use in Claude Code
claude
# Trigger the condition that should run your hook

Hook Best Practices

1. Keep Hooks Fast

{
  "timeout": 5000  // 5 seconds max
}

Slow hooks frustrate users. If a check takes >5 seconds, consider running it asynchronously.

2. Provide Clear Messages

# Bad
exit 1

# Good
echo "BLOCKED: Found 'synergy' in line 42"
echo "Suggestion: Replace with 'collaboration'"
exit 1

3. Use block_on_failure Sparingly

Only block on critical issues:

  • Security vulnerabilities
  • Brand voice violations that would be embarrassing
  • Breaking changes to APIs

Don't block on:

  • Style preferences
  • Optional optimizations
  • Warnings

4. Log Hook Activity

#!/bin/bash
# Add to every hook
echo "[$(date)] Hook: $0, Input: $1" >> ~/.claude/hooks.log

5. Test Hooks in Isolation

# Test before adding to hooks.json
./my-hook.sh "test input"
echo $?  # Check exit code

Debugging Hooks

Hook Not Running?

  1. Check hooks.json syntax:

    jq . ~/.claude/hooks.json
    
  2. Verify trigger pattern matches:

    echo "Write" | grep -E "Write|Edit"
    
  3. Check script permissions:

    ls -la ~/.claude/scripts/
    

Hook Failing?

  1. Run script manually:

    ~/.claude/scripts/my-hook.sh "test"
    
  2. Check logs:

    tail -f ~/.claude/hooks.log
    
  3. Add debug output:

    set -x  # Add to script for verbose output
    

The ACOS Default Hooks

ACOS v6 ships with these default hooks:

{
  "hooks": {
    "SessionStart": [
      {
        "name": "acos-context",
        "script": "echo 'ACOS v6.0 | 25 Commands | 80+ Skills | 40+ Agents'"
      }
    ],
    "PreToolUse": [
      {
        "name": "brand-voice",
        "trigger": "Write",
        "pattern": "\\.mdx$",
        "script": "check-brand-voice.sh"
      }
    ],
    "PostToolUse": [
      {
        "name": "quality-score",
        "trigger": "Write",
        "pattern": "\\.mdx$",
        "script": "calculate-quality.sh"
      }
    ],
    "Notification": [
      {
        "name": "skill-suggestions",
        "pattern": "blog|article|content",
        "message": "Content creation detected. Skills loaded: content-strategy"
      }
    ]
  }
}

Frequently Asked Questions

What are hooks in ACOS?

Hooks are automated scripts that run at specific points in the Claude Code lifecycle. They enable quality gates, brand voice enforcement, and automated workflows without manual intervention.

When do hooks run?

  • SessionStart: When you open Claude Code
  • PreToolUse: Before Claude writes/edits files
  • PostToolUse: After Claude completes a tool action
  • Notification: When specific patterns are detected

Can hooks block Claude from writing?

Yes, if block_on_failure: true is set. Use this for critical quality gates like security checks or brand voice enforcement.

How do I debug a failing hook?

Run the script manually, check the exit code, and review any logs. Add set -x to scripts for verbose output.

Do hooks work with all Claude Code tools?

Hooks can trigger on any tool. Use the trigger property with regex patterns to match specific tools.

Can I have multiple hooks for the same event?

Yes. Hooks run in order defined in the array. If one blocks, subsequent hooks don't run.

Next Steps

  1. Review default hooks โ€” Check .claude/hooks.json in your ACOS install
  2. Add brand voice hook โ€” Customize with your banned phrases
  3. Create a quality hook โ€” Validate content meets your standards
  4. Contribute hooks โ€” Share useful hooks with the ACOS community

Related Articles

Automate quality. Ship with confidence.

GitHub | FrankX

Stay in the intelligence loop

Weekly field notes on AI systems, production patterns, and builder strategy.

Occasional FrankX field notes. Unsubscribe anytime. Privacy details.