CC-301c · Module 1
The --quiet Requirement
3 min read
The --quiet requirement is the most violated rule in hook development and the cause of the most confusing failures. Here is the failure mode: you write a stop hook that runs ESLint. ESLint produces output on stdout — warnings, errors, file paths. Your hook script then console.logs a JSON instruction. But Claude never sees your JSON. It sees ESLint's output as the first stdout content and treats it as the instruction. The result is unpredictable behavior — Claude might try to "fix" the ESLint output as if it were a code file, or it might simply ignore the hook because the output is not valid JSON.
The --quiet flag suppresses stdout output on most CLI tools. eslint --quiet suppresses warnings (but still outputs errors). tsc --noEmit does not have a quiet flag, so you must capture its output: const result = execSync("npx tsc --noEmit 2>&1", { encoding: "utf-8" }). The 2>&1 redirects stderr to stdout so you capture everything. The key is that execSync captures the output in a variable rather than letting it flow to the process's stdout.
There is a subtler form of stdout pollution that even experienced developers miss: npm lifecycle scripts. When you run npx or npm exec, npm may output "npm WARN" or version information to stdout before your tool runs. This noise precedes your JSON instruction and corrupts the protocol. The fix is environment variable suppression: set npm_config_loglevel=silent before running npm commands inside hooks, or use direct binary paths (./node_modules/.bin/tsc) instead of npx.
The clean output contract applies recursively. If your hook script calls a helper script that calls another tool, every layer of the call stack must be quiet on stdout. One noisy tool at any depth breaks the entire hook. This is why the best practice is to test hooks in isolation: run the hook script directly from your terminal, inspect its stdout, and verify the only output is your JSON instruction. If anything else appears — a warning, a version number, a progress message — find it and silence it.