Sociologix
← Latest in AI

Developer tools · · 5 min read

Claude Code hooks: check a website brief after AI edits

Connect a focused Node check to PostToolUse, test the handler with synthetic events, and keep a passed check separate from approval to publish.

By Sociologix Editorial

Official Claude Code documentation artwork titled Automate actions with hooks, featuring the Claude mark.
Official Claude Code hooks-guide sharing artwork, retrieved November 13, 2026. This identifies the documented feature; it is not a screenshot of the local handler running in Claude Code.Image source ↗

Make a small website rule visible after an AI edit

An AI coding session can improve a landing page while accidentally dropping the agreed request destination from its brief. A quick check after edits can flag that drift while the developer is still working, rather than leaving it for the release review.

This AI-assisted editorial guide builds a read-only Node handler for a fictional site-brief.json. It checks a title and a quote-request CTA. Fourteen local handler tests passed on Node 24.19.0 on Windows. The Claude Code configuration follows official documentation checked November 13, 2026; we did not run a Claude Code session or test its hook delivery for this article.

1. Define the small contract you want to check

For this demo, the trimmed title must have a JavaScript string length of 1–120, and requestCta.label a trimmed length of 1–60. These lengths count UTF-16 code units. requestCta.href must equal /request/. That destination is our fictional project’s agreed route. Change the policy deliberately when adapting the example to your own application.

Save the JSON below as site-brief.json in a new demo project folder. The checker accepts additional fields, so it is not a complete brief schema. It also does not inspect HTML, test the request page or prove that a visible button uses this configuration.

{
  "title": "Demo Harbor — project intake",
  "requestCta": {
    "label": "Request a quote",
    "href": "/request/"
  }
}

2. Save a handler that reads the fixed project file

Create .claude/hooks/check-brief.mjs inside the demo project and save the following code there. It uses Node’s built-in file and path modules, so no npm package is needed. Reading stdin as UTF-8 supplies the event JSON; reading the fixed site-brief.json supplies the data to check. [4]

The handler checks the event and tool names itself. For PostToolUse Write or Edit events it checks the same fixed brief, regardless of which file changed. It never takes a shell command from the payload. A failed check emits a short message to stderr without echoing the brief’s contents; success is quiet.

CLAUDE_PROJECT_DIR selects the original project root. It can differ from the event’s cwd after a directory or worktree change. [1] This example intentionally checks that original root, not whichever directory a later tool call enters.

import fs from 'node:fs';
import path from 'node:path';

function fail(message) {
  process.stderr.write('Brief check: ' + message + '\n');
  process.exit(2);
}

let event;
try { event = JSON.parse(fs.readFileSync(0, 'utf8')); }
catch { fail('Hook input must be JSON.'); }
if (!event || typeof event !== 'object' || Array.isArray(event)) {
  fail('Hook input must be an object.');
}
if (event.hook_event_name !== 'PostToolUse' ||
    !['Write', 'Edit'].includes(event.tool_name)) process.exit(0);

const root = process.env.CLAUDE_PROJECT_DIR;
if (!root || !path.isAbsolute(root)) fail('Project root is required.');

// Always inspect this fixed project file, never a command from the payload.
let brief;
try {
  brief = JSON.parse(fs.readFileSync(path.join(root, 'site-brief.json'), 'utf8'));
} catch { fail('site-brief.json must exist and contain valid JSON.'); }
const text = (value, max) => typeof value === 'string' &&
  value.trim().length > 0 && value.trim().length <= max;
if (!brief || Array.isArray(brief) || !text(brief.title, 120)) {
  fail('title must be nonempty text of at most 120 trimmed characters.');
}
if (!brief.requestCta || Array.isArray(brief.requestCta) ||
    !text(brief.requestCta.label, 60) || brief.requestCta.href !== '/request/') {
  fail('requestCta needs a label and the agreed /request/ destination.');
}
// Quiet exit 0 means these brief checks passed, not release approval.

3. Wire it to the documented PostToolUse event

Add this hooks block to the demo project’s .claude/settings.json. Shared project settings apply to that project; merge with existing settings instead of replacing other hooks. [2] PostToolUse runs after a tool succeeds, and the Write|Edit matcher selects those tool names. [3]

The command and args fields use exec form: Node receives the script path as one argument without shell parsing. The explicit timeout is 30 seconds. [1] This is a small synchronous check, not a background publishing job.

Hook commands run automatically once enabled, so review the script before adding it to a real project. We kept this experiment in an isolated demo folder and did not enable a hook in the Sociologix production project.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "node",
            "args": [
              "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-brief.mjs"
            ],
            "timeout": 30
          }
        ]
      }
    ]
  }
}

4. Exercise the handler before asking Claude to use it

From the demo project root, run the PowerShell block below. The first command should finish quietly with LASTEXITCODE equal to 0. For the second run, temporarily change requestCta.href to /other/, then repeat the invocation. Expect exit 2 and feedback naming the required /request/ destination. Restore the fixture afterward.

Our tests launched the exact handler through Node child processes with JSON on stdin and temporary fixture directories. They checked valid Write and Edit events, blank and overlong titles, the wrong destination, a missing CTA, malformed and missing brief files, malformed and null event payloads, an absent project root, and a project path containing spaces from a different working directory.

The remaining two tests confirmed that Bash and PreToolUse events were skipped, even when the brief was absent. Across all 14 cases the checks passed. These tests establish the handler’s local exits and messages. They do not establish that a particular Claude Code installation has loaded the settings or delivered the event.

$env:CLAUDE_PROJECT_DIR = (Get-Location).Path
'{"hook_event_name":"PostToolUse","tool_name":"Write"}' | node .claude/hooks/check-brief.mjs
$LASTEXITCODE
# Change requestCta.href to /other/ and repeat to test feedback.
# Restore /request/ when finished.

5. Verify the real hook and keep release checks separate

In your own Claude Code session, open /hooks and confirm the PostToolUse entry is present. Ask for a harmless edit in the demo, then deliberately break and repair the CTA policy. Inspect the resulting feedback and the file itself. The official guide explains how to confirm hook execution and troubleshoot missing hooks. [3]

For PostToolUse, exit 2 feeds stderr back to Claude; the edit has already happened. It does not undo that edit. [1] The next useful step is repair and recheck, not assuming the old file was restored.

Write|Edit does not cover files rewritten through Bash, an external editor or another unmatched tool. Interruptions can also stop a hook. Keep a repeatable check in your normal review or CI process and test any broader event coverage separately.

A quiet exit only means these title and CTA checks passed. Continue with the actual form submission test, responsive browser review, accessibility checks and your required release approval. Hooks can make a rule easier to notice during AI-assisted development; they do not supply those missing checks.

Sources & further reading

  1. Claude Code hooks reference: events, exec form and exit codes
  2. Claude Code settings: project scope and precedence
  3. Claude Code guide: automate actions with hooks
  4. Node.js 24 file-system API: readFileSync

Make AI-assisted website delivery easier to review

Sociologix can help turn website requirements into focused checks, connect them to your AI development workflow and define the review steps before launch. Bring a sample brief and the rules your project must preserve.

Talk to Sociologix