One day I asked the agent to derive the site’s palette from the client’s logo. The client had no usable logo. The agent did not stop and did not ask. It concluded that the brand had no particular chromatic signature, and invented a palette from the photos on the home page. The agent works in a pipeline I have been putting together since June 2026: it reads a client’s existing site and derives redesign prototypes from it, which I then choose between.
The result was pretty. It had nothing to do with the brand.
I was asking the question of the wrong thing: a logo’s colour gets measured.
Three questions that should never have been prompts
The sorting is simple. If two competent people looking at the same data must land on the same answer, it is a calculation. Three cases left the prompt to become scripts.
Brand colour first. We ignore everything that carries no identity, pixels that are too transparent, near-whites, near-blacks, greys, then take the dominant hue by quantisation. The thresholds are written down, debatable, and above all stable: minimum saturation at 0.22, luminance between 0.06 and 0.94. The same logo always returns the same colour.
Then the business sector, through a score on the words of the client’s actual content, strong terms counting triple and common terms for one. And finally image usability, through a minimum width by role: a logo under 200 px, a hero visual under 1,200 px, is blurry at its intended display size.
None of the three calls a model. And all three can be rerun over two months of archives to check they have not drifted.
A detector’s best result is « nothing »
A strictly black and white logo has no brand colour. The script brand-color.mjs could have returned a mid grey, technically exact and completely wrong. It returns null, and that absence triggers the right decision downstream: a monochrome style, chosen, rather than an invented colour.
Same logic for the sector, with two safeguards rather than one, because a wrong sector is worse than no sector: it orders false trade requirements and an argument order running the wrong way, which nobody will come back to correct. A threshold of 5 points, below which we stay on the generic profile. A minimum gap of 3 points with the runner-up, below which we declare the ambiguity instead of deciding.
An ambiguous detection logs its abstention with the top two of the ranking, and a human decides. The normal case stays silent, no write and no log line. A tool that speaks when it hesitates and stays quiet when it knows is a tool you can leave running.
The whole-word trap
Terms are searched as whole words. Without that guard, « coach » fires on « coaching », and the case that made me wince, « photo » fires on « photocopy ». A printer classified as a photographer, with a photographer’s trade requirements and a site that shows before it talks.
A deterministic detector is reliable when its errors are reproducible, and therefore fixable. That is the practical difference with a model: I can write a test that fails on « photocopy », I cannot write a test that fails on an intuition.
The catalogue goes into the prompt
The detection was catching, after the fact, a problem whose cause lay upstream. The prompt asking the agent to fill in the client record did not even mention the « sector » field in its list. So the agent filled it in from memory, with words that existed nowhere in the catalogue.
The fix fits in one sentence: the real catalogue is injected into the prompt, read from disk at launch. The agent picks from a list that exists instead of inventing a label. Three instructions come with it, all drawn from observed errors. Choose on what the client does. Decide on the visitor when a trade falls under two profiles. Leave the field empty rather than approximate.
It became a general rule of the pipeline. Everything the system knows, the sector catalogue, the styles already assigned to other clients, the images actually present, is given to the agent, never guessed by it.
When the measurement is right and the transport broken
The art direction brief returns a table of colours, each named by the role it feeds. One entry was missing from the label table: the ink, the colour of running text. As a result, every generated brief contained a nameless line next to a hex code. The generator found a dark colour with no job. On one client, it took it for a panel colour and painted whole sections with it. The page was brown, dull, and nobody understood why.
I drew a sentence from it that I left as a comment in the code: a nameless colour always ends up being misused.