brand_preflight
Check HTML/CSS against brand rules: detect off-brand colors, wrong fonts, missing logo, and anti-pattern violations. Returns pass/warn/fail per rule.
Instructions
Check HTML/CSS against brand rules — catches off-brand colors, wrong fonts, missing logo, and anti-pattern violations (drop shadows, gradients, etc.). Pass an HTML string or file path. Mode 'check' (default) runs all compliance checks and returns pass/warn/fail per rule. Mode 'rules' lists all active preflight rules without checking content. Use after generating any visual content to validate brand compliance. Returns overall status and per-check details. NOT for scoring content copy — use brand_audit_content. NOT for brand directory validation — use brand_audit.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| html | Yes | HTML to validate: either a full HTML string (with <style> blocks) or a file path ending in .html (e.g. 'output.html') | |
| mode | No | 'check' (default): validates HTML against all brand rules. 'rules': lists all active rules without running checks. | check |
Implementation Reference
- src/tools/brand-preflight.ts:666-709 (handler)Main handler function for the brand_preflight tool. Accepts 'mode' (check|rules) and 'html' (string or file path). In 'rules' mode, lists active preflight rules. In 'check' mode, resolves HTML (inline or file), then runs all compliance checks (colors, typography, logo, anti-patterns). Returns overall PASS/WARN/FAIL with per-check details.
async function handler(input: Params) { const brandDir = new BrandDir(process.cwd()); if (!(await brandDir.exists())) { return buildResponse({ what_happened: "No .brand/ directory found", next_steps: ["Run brand_start to create a brand system first"], data: { error: ERROR_CODES.NOT_INITIALIZED }, }); } const mode = input.mode || "check"; if (mode === "rules") { return handleRules(brandDir); } // Resolve HTML: if it looks like a file path, read it let html = input.html; if ( !html.includes("<") && (html.endsWith(".html") || html.endsWith(".htm") || html.startsWith("/")) ) { const resolvedPath = resolve(process.cwd(), html); if (!isPathWithinBase(resolvedPath, process.cwd())) { return buildResponse({ what_happened: "File path must be within the current working directory", next_steps: ["Provide an HTML string or a file path within your project"], data: { error: ERROR_CODES.PATH_OUTSIDE_CWD }, }); } try { html = await readFile(resolvedPath, "utf-8"); } catch { return buildResponse({ what_happened: `Could not read file: ${input.html}`, next_steps: ["Provide valid HTML content or a readable file path"], data: { error: ERROR_CODES.FILE_NOT_FOUND, path: input.html }, }); } } return handleCheck(brandDir, html); } - src/tools/brand-preflight.ts:711-722 (registration)Registers the brand_preflight tool on the MCP server with input parameters (html: string, mode: 'check'|'rules') and a description of its functionality.
export function register(server: McpServer) { server.tool( "brand_preflight", "Check HTML/CSS against brand rules — catches off-brand colors, wrong fonts, missing logo, and anti-pattern violations (drop shadows, gradients, etc.). Pass an HTML string or file path. Mode 'check' (default) runs all compliance checks and returns pass/warn/fail per rule. Mode 'rules' lists all active preflight rules without checking content. Use after generating any visual content to validate brand compliance. Returns overall status and per-check details. NOT for scoring content copy — use brand_audit_content. NOT for brand directory validation — use brand_audit.", paramsShape, async (args) => { const parsed = safeParseParams(ParamsSchema, args); if (!parsed.success) return parsed.response; return handler(parsed.data); } ); } - src/tools/brand-preflight.ts:649-664 (schema)Zod schema defining the input parameters for brand_preflight: 'html' (string, required) and 'mode' (enum 'check'|'rules' with default 'check').
const paramsShape = { html: z .string() .describe( "HTML to validate: either a full HTML string (with <style> blocks) or a file path ending in .html (e.g. 'output.html')" ), mode: z .enum(["check", "rules"]) .default("check") .describe( "'check' (default): validates HTML against all brand rules. 'rules': lists all active rules without running checks." ), }; const ParamsSchema = z.object(paramsShape); type Params = z.infer<typeof ParamsSchema>; - src/tools/brand-preflight.ts:594-643 (helper)Core check logic: loads brand identity, parses HTML with cheerio, runs color checks, typography checks, logo presence checks, and anti-pattern matchers. Returns overall PASS/WARN/FAIL with per-check details.
async function handleCheck(brandDir: BrandDir, html: string) { const identity = await brandDir.readCoreIdentity(); let antiPatterns: AntiPatternRule[] = []; if (await brandDir.hasVisualIdentity()) { const vi = await brandDir.readVisualIdentity(); antiPatterns = vi.anti_patterns || []; } let clientName = ""; try { const config = await brandDir.readConfig(); clientName = config.client_name || ""; } catch { // Non-critical — logo checks just won't match by name } // Parse HTML const $ = cheerio.load(html); const css = extractAllCss($); // Run all checks const checks: PreflightCheck[] = [ ...checkColors(css, identity), ...checkTypography(css, identity), ...checkLogo($, identity, clientName), ...checkAntiPatterns(css, antiPatterns), ]; // Compute summary const pass = checks.filter((c) => c.status === "pass").length; const warn = checks.filter((c) => c.status === "warn").length; const fail = checks.filter((c) => c.status === "fail").length; const overall = fail > 0 ? "FAIL" : warn > 0 ? "WARN" : "PASS"; const nextSteps: string[] = []; if (fail > 0) nextSteps.push("Fix failing checks (hard anti-patterns) before shipping"); if (warn > 0) nextSteps.push("Review warnings — some may be intentional deviations"); if (fail === 0 && warn === 0) nextSteps.push("All checks pass — content is brand-compliant"); return buildResponse({ what_happened: `Preflight ${overall}: ${pass} pass, ${warn} warn, ${fail} fail`, next_steps: nextSteps, data: { overall, summary: { pass, warn, fail }, checks: checks as unknown as Record<string, unknown>[], }, }); } - src/tools/brand-preflight.ts:568-592 (helper)Handler for 'rules' mode: compiles all preflight rules from brand identity (colors, typography, logo, anti-patterns) and returns them without running checks.
async function handleRules(brandDir: BrandDir) { const identity = await brandDir.readCoreIdentity(); let antiPatterns: AntiPatternRule[] = []; if (await brandDir.hasVisualIdentity()) { const vi = await brandDir.readVisualIdentity(); antiPatterns = vi.anti_patterns || []; } const rules = compileRules(identity, antiPatterns); return buildResponse({ what_happened: `Compiled ${rules.length} preflight rules from brand system`, next_steps: [ "Run brand_preflight with mode 'check' and HTML content to run compliance checks", rules.some((r) => !r.checkable) ? "Some rules are not checkable — add more data to core-identity.yaml" : "All rules are checkable", ], data: { rule_count: rules.length, rules: rules as unknown as Record<string, unknown>[], }, }); }