NO_COLOR and TTY detection
Why it matters
When mytool list > out.txt writes \x1b[32mOK\x1b[0m into the file, the user opens out.txt and sees escape-code garbage. When CI logs capture ANSI codes as ^[[32m, grep patterns break. When a blind user's screen reader hits color codes, output becomes unintelligible. The NO_COLOR convention (no-color.org) and TTY detection exist for exactly this reason — ignoring them corrupts piped output, log files, and accessibility tooling.
Severity rationale
Medium because raw ANSI codes in piped output or log files corrupt downstream consumers and break accessibility.
Remediation
Check process.env.NO_COLOR and process.stdout.isTTY before emitting ANSI codes, or use a library like picocolors that does this automatically. Wire the check once in src/cli/lib/color.ts:
import pc from 'picocolors'
// picocolors honors NO_COLOR and isTTY automatically
console.error(pc.green('Success'))
Test with NO_COLOR=1 mytool list and mytool list | cat.
Detection
-
ID:
no-color-support -
Severity:
medium -
What to look for: List all colored output locations in the CLI. For each, check for
NO_COLORenvironment variable support (see https://no-color.org). Check for TTY detection that disables colors and interactive elements when output is piped. In Node.js, look for chalk/picocolors withNO_COLORsupport, orprocess.stdout.isTTYchecks. In Python, look for--no-colorflag orNO_COLORenv var handling. In Go, look forisattychecks or--no-colorsupport. Check that--no-colorflag orFORCE_COLOR=0/NO_COLOR=1disables all ANSI escape codes. -
Pass criteria: The CLI respects the
NO_COLORenvironment variable by suppressing all ANSI color codes when it is set. When stdout is not a TTY (piped), colors are automatically disabled. A--no-colorflag is recommended but not required ifNO_COLORenv var is supported — 100% of colored output must be suppressed when NO_COLOR environment variable is set. Report: "X colored output points found, all Y respect NO_COLOR." -
Fail criteria: Colors are output regardless of
NO_COLORenv var, or colors are output when stdout is piped to a file/process, or no color control mechanism exists and the CLI outputs ANSI escape codes. -
Skip (N/A) when: The CLI produces no colored output — all output is plain text with no ANSI codes, chalk, picocolors, or equivalent. All checks skip when no CLI entry point is detected.
-
Detail on fail:
"CLI uses chalk for colored output but does not check NO_COLOR env var or stdout.isTTY — colors will corrupt piped output"or"Colored output sent even when piped: 'mytool list > out.txt' produces ANSI escape codes in the file" -
Remediation: Respect the
NO_COLORconvention and detect pipe contexts:// Node.js — picocolors respects NO_COLOR automatically import pc from 'picocolors' // picocolors checks NO_COLOR and stdout.isTTY out of the box console.error(pc.green('Success')) // no color when piped or NO_COLOR set // Manual check if using raw ANSI codes const useColor = process.stdout.isTTY && !process.env.NO_COLOR# Python — click respects NO_COLOR in recent versions import os use_color = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() and not os.environ.get('NO_COLOR')
Taxons
History
- 2026-04-18·v1.0.0·Initial import from cli-quality·automated