Generate.ts intent gate
Generate.ts refuses to run unless it gets --intent=<name> (or the explicit --freeform-confirmed opt-out), and exits non-zero with the intent lookup table. The rule was markdown-only until it was silently ignored and one session produced a run of rejected diagrams (incident 2026-04-30); it now lives in code. The --intent=<name> flag asserts that the matching intent file was read and its prompt template followed: the intent templates encode the technique, palette, composition rules and validation gate the bare model fails to honor, and a freeform prompt shipped straight to Generate.ts is refused.
The one exception: the user explicitly says "freeform" / "skip the intent" / "just run Generate.ts directly with this prompt: ...". Then pass --freeform-confirmed, which logs the explicit opt-out to stderr for audit. Without that instruction from the user, pick the matching intent and pass --intent=<name>.
If no intent matches the request, stop and surface it to the user before generating, proposing (a) the closest existing intent, (b) Visualize.md as the generic catch-all, or (c) a new intent created first through the CreateSkill skill.
Output staging
Every generated image, in every intent, is rendered first into a working directory outside Downloads (for example scratchpad/art/<slug>/, written $ART_DIR in the commands below) or the staging directory its intent names, never directly into Downloads or a project's public/images/ directory: images pushed straight to repos have failed several times. Once the image has passed the quality loop below and the verification under Tool contract, it is handed off with bun ~/.claude/skills/ArtDirection/Tools/Deliver.ts --artifact <file> --to ~/Downloads. A file is copied into a project (e.g., cms/public/images/) only after that hand-off, and the WebP and thumbnail versions are made from the staged file. Whether the principal approves before that move is the intent's rule: the Essay intent wires its picked winner into the site without handing back (principal directive, 2026-09-22), and an intent that says nothing waits for the principal's review.
Quality loop
Nothing this skill produces reaches the principal as a first draft (principal directive, 2026-09-17). The artifact goes through Skill("ArtDirection"): a direction council before new or large work, then the cross-vendor critique panel (skills/ArtDirection/Tools/Critique.ts) scores it against the rubric and names defects, then this skill iterates on those defects until the bar or reports the shortfall. For still images, one round is one command: Tools/EvalRound.ts runs the asserts, blind describer and meaning ladder, cross-vendor critique, and flipped tournament in parallel, picks the winner in code, and takes 2 minutes or less (contract: Tools/EvalRound.help.md). Hand-over is skills/ArtDirection/Tools/Deliver.ts, which refuses without a passing critique. Record the principal's verdict with skills/ArtDirection/Tools/Calibrate.ts.
Vendors
Generate.ts ships only the models listed under Tool contract. Removed model names (gpt-image-1, gpt-image-2, the dual-provider compare mode) exit with an error pointing at nano-banana-pro. Which image vendors this install allows is the principal's call, recorded in <configRoot>/LIFEOS/USER/CUSTOMIZATIONS/SKILLS/Art/PREFERENCES.md § Vendors; read it before changing a model path. Do not add a vendor as a substitute when a round fails: adding a new vendor to any lane requires the principal's explicit approval.