Teach a Coding Agent Your Brand Rules

Write a design.md brand spec, then build checks that catch broken rules.

Introduction

30 Second Summary

Ask a coding agent for a landing page and you get the same purple gradient as everyone else. The agent has no idea what your brand looks like, so it reaches for the average of everything it has ever seen.

In this project, you will write a design.md file that holds your colours, type and rules, then prove it changed what your agent builds. You will also write checks that fail when a rule gets broken.

What You'll Build

By the end, you'll have two screenshots of the same landing page side by side, one generic and one unmistakably yours, plus a check that goes red the moment your agent drifts off brand.

By the end of this project, you'll have:

  • A design.md file you can drop into any repo, holding your colours, type scale and spacing steps in a form an agent can actually act on.
  • A before and after pair of the same landing page from the same prompt, where the second one looks like your brand and you can point at exactly why.
  • Three checks that read the built page and go red on a broken rule, so you find out which of your rules was written too vaguely to survive.
  • A live URL you can send to someone, with the on-brand page behind it.
  • Secret Mission: Add a fourth check that catches the rule your agent broke silently, then feed the failure back into design.md so the next run passes first time.

Are there any prerequisites?

You need a coding agent you already run, a Git repo and any static or Next.js starter. Nothing here needs a GPU or a paid seat beyond the agent you already pay for.

Before We Start

Before you touch a single file, lock in what you're building and why it matters. Naming the goal now makes every design decision later a lot easier to judge.

Generate a Generic Landing Page

Your repo is set up and your coding agent is ready to go. Time to put it to work.

Ask a coding agent for a landing page and you tend to get the same page everyone else gets. A purple gradient hero, a default sans-serif, spacing that came from nowhere in particular.

You can only prove you fixed that if you can show what it looked like first. In this step you capture that baseline and save it as evidence.

In this step, get ready to:
  • Prompt your coding agent for a landing page with no brand guidance at all.
  • Open the generated page in your browser and see what the agent defaults to.
  • Save a screenshot as screenshots/generic.png and commit the baseline.
Prompt your agent with no brand guidance

The prompt you are about to send is deliberately bare. It says what the page contains and nothing about how it should look.

  • Switch back to the terminal you used to set up your repo.
  • Move into your repo by running this command:
cd ~/Desktop/brand-rules-demo
  • Start your coding agent from inside this folder, the same way you started it earlier.
  • Allow your agent to create and edit files when it asks you for permission.
  • Copy this prompt:
Build a single-page landing page for a note-taking app called Northwind Notes.

Use plain HTML and CSS only. No frameworks.
Put the markup in index.html and the styles in styles.css, both at the root of this repo.

The page needs a hero section with a headline, a subheading and a call to action button, plus a row of three feature cards below it.

Do not ask me any questions. Build it now.
  • Paste the prompt into your agent and press Enter.

Why give the agent nothing to work with?

Every instruction you leave out is a decision the agent makes for you. Colour, type, spacing and rhythm all get filled in from its training defaults.

This run is your control. Whatever it produces is what your brand looks like to an agent that has never been told about it.

  • Confirm the files exist by running:
ls

You should see index.html and styles.css in the output.

Agent didn't create the files?

Check that you started the agent from inside your repo folder. Agents write files relative to where they were launched.

If the agent replied with questions instead of code, send the prompt again and add that it should proceed without asking.

My coding agent replied with questions instead of writing index.html and styles.css. How do I get it to just build the files?

Open the page in your browser

The agent wrote plain HTML and CSS, so you can open the file straight from disk.

Before you open it, make a guess. What colour do you think the hero section will be, and what font?

  • Open the page in your browser by running the command for your system:

macOS

open index.html

Windows

start index.html

Chances are you are looking at a purple gradient hero, a centred headline in a default sans-serif, and three evenly spaced feature cards.

That is the intended result. This page is the problem you are here to solve.

Why agents keep landing on the same look

An agent with no brand input picks the most statistically ordinary choice at every decision point. Purple gradients and system fonts are what the internet is made of.

The output is not wrong. It is average, and average is exactly what a brand cannot afford to look like.

Save the baseline and commit it

A screenshot is the only way to compare this page against the branded one later. Save it now, while the generic version still exists.

  • Create a folder for your screenshots by running this command:
mkdir screenshots
  • Press Cmd+Shift+4 (macOS) or Win+Shift+S (Windows) to start a screen capture.
  • Drag a box around the whole landing page in your browser.
  • Save the image into your screenshots folder with the name generic.png.
  • Confirm the screenshot landed in the right place by running:
ls screenshots

You should see generic.png listed.

Screenshot not in the folder?

On macOS a screen capture saves to your Desktop by default. Drag the file into screenshots and rename it.

On Windows the capture goes to your clipboard first. Paste it into an image editor, then save it into the folder.

Where did my screenshot save and how do I move it into my project folder?

  • Commit your baseline by running these commands:
git add .
git commit -m "Add generic landing page baseline"

Before you run the next command, what do you expect Git to report now that the page and the screenshot are committed?

  • Check the state of your repo by running:
git status

Git should report that there is nothing left to commit. Your generic page and its screenshot are now saved as the before half of the comparison.

You have proof of what an agent does with no direction. Next up, you'll write the design.md file that gives it some.

Write Your Brand Rules in design.md

You now have a landing page and a screenshot that proves the problem. Asked for a page with no guidance, the agent reached for the same gradient hero it hands everyone else.

The agent was not being careless. It had nothing to follow, so it fell back on its own defaults.

In this step you give it something to follow. One file, design.md, holding your colours, type scale, spacing steps and three rules the agent must not break.

In this step, get ready to:
  • Create a design.md file at the top of your repo.
  • Fill it with your colour palette, type scale and spacing steps.
  • Write three rules the agent must not break.
Create design.md at the top of your repo
  • Switch back to the terminal you used in Step 1.
  • Confirm where you are by running this command:
pwd

The path that prints ends with the project folder you created in Step 1.

  • Create the file your agent will read by running this command:
touch design.md
  • Confirm the file exists by running this command:
ls

design.md now appears in the listing alongside your landing page files.

Don't see design.md in the list?

  • Check the path from pwd ends with your project folder from Step 1. If it does not, move into that folder with cd and run the command again.
  • Check you typed design.md and not designs.md. A stray letter creates a file your agent will never look for.

Why isn't design.md showing up when I run ls?

Why does this file sit at the top of the repo?

A coding agent reads the files you point it at. Keeping design.md at the top of the repo makes it trivial to name in a prompt.

It is a plain Markdown file, so the agent parses it as easily as you read it.

Fill in your colours, type and spacing

A mood board tells an agent nothing. Values it can copy into CSS tell it everything.

  • Return to your code editor and open design.md.
  • Give the agent concrete values to copy by pasting this into the empty file:
# Design

## Colours
- Background: #0B0B0F
- Surface: #16161D
- Text: #F2F2F2
- Muted text: #9A9AA5
- Accent: [[BRAND_ACCENT="your accent hex, e.g. #FF5A1F"]]

## Type
- Family: [[BRAND_FONT="your heading font, e.g. Inter"]]
- Display: 48px / 1.1 / 600
- Heading: 32px / 1.2 / 600
- Body: 16px / 1.6 / 400
- Small: 14px / 1.5 / 400

## Spacing
- Steps: 4px, 8px, 16px, 24px, 48px, 96px
- Section padding: 96px top and bottom
- Gap between related items: 16px

What is in this file?

  • Colours gives every surface a hex value, so the agent never has to pick one.
  • Type pins size, line height and weight for four roles, which stops the agent inventing a fifth.
  • Spacing lists the only gaps allowed on the page. Anything off this ladder is a mistake you can spot.

Swap the example hex values for your own brand's palette. The two placeholders are the ones your checks will read in Step 4.

  • Save design.md.
  • Check the values landed by running this command in your terminal:
cat design.md

Your three headings print back with the values underneath each one.

cat printing nothing back?

  • An empty output means the file was never saved. Save it in your editor, then run the command again.
  • A No such file or directory response means your terminal is in a different folder from the file you edited.

Why is cat design.md coming back empty?

Write three rules the agent must not break

Values describe the palette. Rules describe what counts as wrong.

  • In design.md, move your cursor to the end of the file, below the ## Spacing list.
  • Give the agent three lines it can be judged against by pasting this below that list:

## Rules the agent must not break
1. Backgrounds stay flat. No gradients anywhere on the page.
2. Every font-family declaration uses [[BRAND_FONT="your heading font, e.g. Inter"]] and nothing else.
3. Every button background is the accent colour [[BRAND_ACCENT="your accent hex, e.g. #FF5A1F"]].

What do these three rules do?

Each rule names a thing that can be read straight off the built page. A gradient is either in the CSS or it is not.

Three is the ceiling on purpose. A list of fifteen rules is a list an agent quietly drops half of.

  • Save design.md.
  • Check all four sections are in the file by running this command again:
cat design.md

The output now ends with your three numbered rules under the ## Rules the agent must not break heading.

Rules missing from the output?

  • Check the rules went into design.md and not into your landing page file. Editor tabs are easy to mix up.
  • Check the heading starts with ## and a space. Without the space it renders as plain text.

Why are my rules missing from the cat output?

✔️ Awesome, I've got everything!

Great, double check you've saved design.md before moving on.

ⓧ I'd like to double check the full code

Here is the whole file, with the example values still in place.

# Design

## Colours
- Background: #0B0B0F
- Surface: #16161D
- Text: #F2F2F2
- Muted text: #9A9AA5
- Accent: [[BRAND_ACCENT="your accent hex, e.g. #FF5A1F"]]

## Type
- Family: [[BRAND_FONT="your heading font, e.g. Inter"]]
- Display: 48px / 1.1 / 600
- Heading: 32px / 1.2 / 600
- Body: 16px / 1.6 / 400
- Small: 14px / 1.5 / 400

## Spacing
- Steps: 4px, 8px, 16px, 24px, 48px, 96px
- Section padding: 96px top and bottom
- Gap between related items: 16px

## Rules the agent must not break
1. Backgrounds stay flat. No gradients anywhere on the page.
2. Every font-family declaration uses [[BRAND_FONT="your heading font, e.g. Inter"]] and nothing else.
3. Every button background is the accent colour [[BRAND_ACCENT="your accent hex, e.g. #FF5A1F"]].

Write rules a check can read

A rule like "keep the page clean" cannot fail. There is no value on the built page that proves it true or false.

Your three rules each point at something readable: a gradient, a font family, a button colour. In Step 4 you will find out which of them is still looser than you thought.

Before you run the next prompt, which of your three rules do you think the agent will restate most loosely?

  • Test that the agent can actually read your file by sending it this prompt:
Read design.md in this repo and list the three rules I must not break, in your own words.

The agent reads back three rules that match the ones you wrote. Any rule it paraphrases into something fuzzier is the one to watch in Step 4.

Agent says it can't find the file?

A file on disk is not the same as a file in context. Some agents only read what you name or attach.

  • Check your agent session was started from the same folder your pwd printed earlier.
  • Attach or reference design.md explicitly using whatever file-reference syntax your agent supports, then send the prompt again.

How do I put a specific file into my coding agent's context?

Your brand is written down and your agent can read it back. Next up, you'll run the exact same prompt from Step 1 again, this time with design.md in context, and put the two pages side by side.

Regenerate the Page With design.md in Context

Your design.md is saved in your repo root, and so far it has changed nothing. A file sitting on disk is invisible to your coding agent until you hand it over.

The only honest way to prove the file matters is to change one variable and nothing else. You'll run the exact same landing page prompt again, with the rules in context this time.

Two pages from one prompt gives you a before and after you can point at. That pair is the evidence everything else in this project rests on.

In this step, get ready to:
  • Rerun your original landing page prompt with design.md in the agent's context.
  • Save a screenshot of the branded result as screenshots/branded.png.
  • Put the two screenshots side by side and check the page against your three rules.
Commit the generic page before you overwrite it

The agent is about to write over the same files it wrote the first time. Once your generic page is gone, you have no way to look at what actually changed in the code.

A commit keeps that first version recoverable. Git holds onto it while the agent rewrites your files.

  • Switch back to the terminal you used earlier.
  • Save the generic version by running these commands:
git add -A
git commit -m "Generic landing page before design.md"
  • Read the output. You should see a summary line naming your commit message and a count of the files it saved.

Git says there is nothing to commit?

You may have already committed this work at the end of an earlier step, which means your generic page is safe either way.

If Git asks you to set an identity before it will commit, run the two configuration commands it prints, then run the commit again.

Why won't my commit go through?

Feed design.md to the agent and rerun your prompt

An agent follows the rules it can read, not the rules that exist in your folder. This is the most common way this whole technique fails quietly.

  • Switch back to your code editor.
  • Copy the full contents of design.md.
  • Switch back to your coding agent.
  • Build your new prompt using this structure:
Follow the design system below exactly. Do not break any of its rules.

[[DESIGN_MD="paste the full contents of your design.md here"]]

[[ORIGINAL_PROMPT="paste the exact landing page prompt you used the first time"]]

Why paste the file instead of naming it?

Your agent acts on whatever sits inside its context window. Mentioning a filename does not guarantee the agent ever opened it.

Pasting the Markdown in full removes that doubt. Every colour, step and rule is right in front of the model when it writes the page.

The second half of the prompt has to be identical to your first attempt. If you reword it, you no longer know which change produced the new page.

  • Send the prompt.
  • Wait for the agent to finish writing files before you touch anything.
  • Switch back to your terminal.
  • Check which files the agent actually changed by running this command:
git status

Your landing page files show up as modified against the commit you just made. That list is your proof the agent wrote something.

No files listed as modified?

The agent may have written into a different folder. Check that the terminal and the agent are both pointed at the same project directory.

Some agents ask for permission before editing files on disk. Scroll back through the conversation and approve any request that is still waiting.

Why didn't my agent change any files?

Before you look at the page, make a call. Which of your three rules do you think the agent followed, and which one do you think it fudged?

macOS

  • Open the regenerated page in your browser by running this command:
open index.html

Windows

  • Open the regenerated page in your browser by running this command:
start index.html

The page loads in your own colours, type and spacing. The generic look from your first attempt is gone.

Your project runs on a dev server instead?

If your starter serves the page rather than opening a file directly, start it the way you did in the first generation and load the local URL it prints.

A stale page usually means the browser cached the old build. A hard refresh clears it.

Screenshot the branded page and compare the two

Your memory of the generic page is already softening. A side by side pair is the only version of this comparison you can show someone else.

  • Press Cmd+Shift+4 (macOS) or Windows+Shift+S (Windows) to start a screen capture.
  • Capture the whole landing page in your browser window.
  • Save the image as branded.png inside your screenshots folder.
  • Confirm both screenshots are in place by running this command:
ls screenshots

You should see branded.png and generic.png listed together.

Only one file listed?

Screen capture tools default to saving on the Desktop. Move the new image into your screenshots folder and rerun the command.

Check the extension too. A file saved as branded.jpg will not match the name the rest of this project uses.

  • Open the screenshots folder in Finder (macOS) or File Explorer (Windows).
  • Open generic.png.
  • Open branded.png.
  • Drag the two windows so they sit side by side on screen.

One prompt produced both of these. The only thing that changed between them is the file you wrote.

  • Switch back to design.md in your editor.
  • Check the branded screenshot against each of your three rules in turn.
  • Note which rules the page follows and which one it only half respects.

When one rule lands softer than the others

A rule the agent half followed is usually a rule written as a feeling rather than a value. Wording like clean or modern gives the model nothing to obey.

Hold onto whichever rule looks weakest here. It is the one worth arguing with later.

Your two screenshots prove the file changed the output. Next up, you'll write checks that read the built page and fail on a broken rule, so you stop judging this by eye.

Write Checks That Enforce Your Rules

Your two screenshots are sitting side by side, and the branded one clearly won. That comparison is still only your eyes, and eyes get tired.

A design rule only counts if something other than you can tell when it has been broken. In this step you turn the three rules in design.md into three small checks that read the built page and report PASS or FAIL.

One of those checks is very likely to fail, and that is the useful part. The rule it fails on is the one you wrote too vaguely for anyone, agent or script, to actually follow.

In this step, get ready to:
  • Create a checks script in your repo that reads the built landing page.
  • Write one check for each of the three rules in design.md.
  • Run all three checks and find out which rule your page breaks.
Create your checks file

A check needs something that can open your built page as plain text and inspect it. Node.js runs a single JavaScript file straight from your terminal, with no build tooling and nothing to install.

  • Switch back to the terminal you used earlier.
  • Check that Node.js is available by running this command:
node --version

✔️ I see a version number

Node.js is ready, so your checks can run straight from the terminal.

ⓧ Command not found

  • Open the Node.js website in your browser.
  • Download the installer for your operating system.
  • Run the installer and accept the defaults.
  • Return to your terminal and confirm the install by running this command again:
node --version

You should now see a version number printed back.

  • Confirm your terminal is in your project folder, the one holding design.md and index.html.
  • Create a checks folder with an empty script inside it by running these commands:

macOS

mkdir checks
touch checks/check_brand.js

Windows

mkdir checks
New-Item checks/check_brand.js
  • Confirm the file exists by running:
ls checks

You should see check_brand.js listed in the output.

  • Open checks/check_brand.js in your editor.
  • Give your script something to read by pasting in this loader:
// Read the built landing page so the checks can inspect it as plain text.
const fs = require("fs");

const html = fs.readFileSync("index.html", "utf8");
const css = fs.readFileSync("styles.css", "utf8");
const page = html + css;

// Broken rules collect here so the script can report a total at the end.
const failures = [];

// Every check prints one line: the rule, whether it passed, and what broke it.
function check(rule, pass, detail) {
  console.log((pass ? "PASS" : "FAIL") + "  " + rule + (pass ? "" : "  ->  " + detail));
  if (!pass) failures.push(rule);
}

console.log("Checking " + page.length + " characters of markup and CSS");

What does this code do?

  • The two readFileSync calls pull your markup and your styles in as strings.
  • Joining them into page means one check can catch a colour whether it lives in the stylesheet or in an inline style.
  • The check helper is the shape every rule will use, so each rule stays about four lines long.
  • Save checks/check_brand.js.
  • Prove the script can find your page by running it from your project folder:
node checks/check_brand.js

You should see one line reporting how many characters of markup and CSS were loaded.

Script cannot find your files?

If Node reports a missing file, your stylesheet probably has a different name, or your styles live inside index.html. Point that line at your real stylesheet, or at index.html a second time.

If Node refuses the require line, your project is set up as an ES module. Rename the file to check_brand.cjs and run that path instead.

My brand check script will not run

Write the colour and type checks

Your first rule is the easiest one to test, because a palette is a finite list. Any hex code on the page that is not on that list is a rule break.

  • Scroll to the bottom of checks/check_brand.js.
  • Add your palette check by pasting this in below the last line:
// Rule 1: every hex colour on the page must come from the design.md palette.
const palette = "[[BRAND_PALETTE="#101014, #f5f3ef, #2f6df6"]]"
  .split(",")
  .map(hex => hex.trim().toLowerCase());

// Collect every hex colour on the page, then keep the ones the palette does not list.
const used = (page.match(/#[0-9a-fA-F]{3,8}/g) || []).map(hex => hex.toLowerCase());
const offPalette = [...new Set(used)].filter(hex => !palette.includes(hex));

check("Colours come from the design.md palette", offPalette.length === 0, offPalette.join(", "));

What does this code do?

  • Replace the sample hex codes with the exact palette you listed in design.md, separated by commas.
  • The pattern #[0-9a-fA-F]{3,8} grabs every hex colour on the page, short form and long form.
  • Both sides are lowercased first, so a stray uppercase hex does not get reported as a rule break.
  • Save checks/check_brand.js.
  • See your first rule graded by running the script again:
node checks/check_brand.js

A second line appears, marked PASS or FAIL for the colour rule. Any off-palette colours are listed after the arrow.

Every colour reported as off-palette?

  • Check that your palette values include the leading hash, since the check compares full hex strings.
  • Check whether your page writes colours as rgb() values, which this check does not read.

Help me read my colour check output

Your second rule is the type scale. Font sizes are a finite list too, so the same shape of check works.

  • Add the type scale check at the bottom of checks/check_brand.js by pasting this in:
// Rule 2: every font size must be one of the steps in the design.md type scale.
const typeScale = "[[TYPE_SCALE="14px, 16px, 20px, 32px, 48px"]]"
  .split(",")
  .map(size => size.trim());

// Pull the value out of every font-size declaration on the page.
const sizeLines = page.match(/font-size:\s*[^;{}]+/g) || [];
const usedSizes = [...new Set(sizeLines.map(line => line.split(":")[1].trim()))];
const offScale = usedSizes.filter(size => !typeScale.includes(size));

check("Font sizes come from the type scale", offScale.length === 0, offScale.join(", "));

What does this code do?

  • Replace the sample sizes with the exact steps from your type scale, written the same way your CSS writes them.
  • Splitting each declaration on the colon leaves just the value, so usedSizes holds every distinct size the page uses.
  • This one is stricter than it looks. A size in rem will not match a scale written in pixels, and that mismatch is worth knowing about.
  • Save checks/check_brand.js.
  • Grade both rules at once by running the script again:
node checks/check_brand.js

You now get two graded lines, one for colour and one for type. Two of your three rules are enforceable by something other than your eyes.

Write the spacing check and run the full set

Your third rule covers spacing. Every pixel value in a margin, padding or gap should land on a multiple of your base spacing step.

  • Add the spacing check at the bottom of checks/check_brand.js by pasting this in:
// Rule 3: every pixel spacing value must be a multiple of the design.md spacing step.
const step = Number("[[SPACING_STEP="8"]]");

const spacingLines = page.match(/(?:margin|padding|gap)[a-z-]*:\s*[^;{}]+/g) || [];
const spacingValues = spacingLines.flatMap(line => line.split(":")[1].trim().split(/\s+/));
const offGrid = [...new Set(spacingValues)]
  .filter(value => value.endsWith("px"))
  .filter(value => Number(value.replace("px", "")) % step !== 0);

check("Spacing values sit on the spacing scale", offGrid.length === 0, offGrid.join(", "));

console.log("");
console.log(failures.length + " of 3 checks failed");

What does this code do?

  • Replace the sample step with your own base spacing number from design.md.
  • Shorthand like padding: 16px 24px is split on whitespace, so each value is graded on its own.
  • The two closing lines print a running total, which is the number you will care about for the rest of the project.

✔️ Awesome, I've got everything!

Great, double check you have saved your file before you run it.

ⓧ I'd like to double check the full code

Scroll up and confirm your checks/check_brand.js holds these four blocks, in this order:

  • The loader, ending with the line that prints how many characters were checked.
  • Rule 1, the palette check.
  • Rule 2, the type scale check.
  • Rule 3, the spacing check, followed by the two summary lines.
  • Save checks/check_brand.js.

Before you run this, which of your three rules do you think your branded page will break? Pick one, then run the checks and find out.

node checks/check_brand.js

You get three graded lines and a total. Read the FAIL line and the values printed after the arrow.

Script stopped instead of printing three lines?

  • Check that your spacing step is a plain number with no unit, since the script converts it with Number.
  • Check that each pasted block sits below the previous one, not inside it.

Why does my checks script stop early?

✔️ At least one check says FAIL

This is the result the step is after. Your agent followed the rules it could act on, and broke the one it could not.

Look at the failing rule as you wrote it in design.md. It almost certainly names a feeling rather than a value, which is why the page drifted off it.

ⓧ All three checks say PASS

Three passes on the first run usually means a check is reading less of the page than you think.

  • Open your built page and find a value your rule should reject, such as an odd padding number.
  • Confirm your check reads the file that value lives in, and the unit it is written in.
  • Run the checks again once you have widened the check:
node checks/check_brand.js

A check that can never fail is not enforcing anything, so keep going until at least one rule is graded honestly.

You now have a rule your page provably breaks and a script that says so out loud. Next up, you rewrite that rule in language the agent can act on, then rerun both to watch the FAIL turn into a PASS.

Fix the Vague Rule and Rerun

Last step you ran your three checks and at least one of them failed. That failure was the whole point of writing the checks.

A check fails when a rule in design.md is too loose for a machine to enforce. The agent read your rule, made a reasonable guess, and the guess did not match what your check was looking for.

In this step you turn that loose rule into an exact value. Then you rerun the agent and the checks to prove the rewrite worked.

In this step, get ready to:
  • Find the rule in design.md that your failing check pointed at.
  • Rewrite that rule with an exact, measurable value.
  • Rerun the agent and the checks until all three pass.
Rerun your checks and read the failure
  • Return to your terminal, in the same folder as design.md.
  • See the failure message again by running this command:
[[CHECKS_COMMAND="node checks.js"]]

The output names which of your three checks failed. That check is the one guarding your vague rule.

  • Read the assertion inside the failing check and note the exact value it looks for.
  • Open design.md in your editor and find the rule that check was written for.

What a failing check is telling you

Your check reads the built page's HTML and CSS and asserts one exact thing about it. It has no room to interpret.

The agent does have that room, so it filled the gap with its own taste. The failure is the gap between the two, and it points straight at the rule you wrote too loosely.

Rewrite the vague rule with an exact value

A rule an agent can follow names a value it can copy. Anything that describes a feeling leaves the agent guessing.

  • In design.md, find the rule your failing check pointed at:
- [[VAGUE_RULE="Headings should feel generous and airy."]]
  • Replace the loose wording with the exact value your check looks for, so the rule now reads like this:
- [[SPECIFIC_RULE="Headings use a font-size of 48px and a margin-bottom of 32px."]]

What makes a rule checkable?

A checkable rule names the property and the value in the same sentence. The agent copies it and your check reads it back.

  • Name one property per rule, so a failure points at one line.
  • Give the value in the unit your check reads, such as a hex code, a pixel value, or a font name.
  • Drop adjectives like generous, clean, or modern. Nothing can measure them.
  • Save design.md.

Before you rerun the checks, do you think the failing one passes now that the rule is exact?

  • Find out by running your checks again:
[[CHECKS_COMMAND="node checks.js"]]

The same check still fails. You changed the rule, but the page sitting in your repo is still the one the agent built from the old wording.

Checks erroring instead of failing?

A crash is different from a failure. If your script stops before it reports a pass or fail, it usually cannot find the built page file at the path you hardcoded.

Confirm you are running the command from the same folder your checks expect. If it still crashes, ask why does my checks script crash instead of reporting a failure?

Rerun the agent and watch all three checks pass

The agent only follows design.md when the file is in its context. Sitting in the repo is not enough, you have to point the agent at it.

  • Switch back to your coding agent, in the same folder as design.md.
  • Give it the same landing page prompt you used before, with design.md in its context.
  • Approve the file edits it asks for so it can rewrite the page.
  • Rebuild the page the same way you did earlier, so your checks read the new output.

This time the agent has a value to copy instead of a description to interpret.

Before you rerun the checks, which of the three do you expect to pass this time?

  • Check your prediction by running your checks one more time:
[[CHECKS_COMMAND="node checks.js"]]

All three checks pass. The rule the agent kept breaking is now a value it can copy.

Still seeing one check fail?

Confirm the agent actually rewrote the page. If the file timestamp has not moved, the prompt ran without design.md in context and the old markup is still on disk.

If the page did change and the check still fails, your rule and your assertion are measuring different things. Ask why does my check still fail after the agent followed the rule?

Your design.md now holds three rules a machine can enforce. Next up, you'll deploy the page and open the live URL.

Deploy the Landing Page

All three checks pass, so your landing page now honours every rule in design.md. That proof lives on your laptop and nowhere else.

A design spec earns its keep when other people can see the result. In this step you put the passing version on a public URL and check the rules survived the trip.

In this step, get ready to:
  • Commit the passing landing page and design.md to your Git repository.
  • Deploy the page to Vercel from your terminal.
  • Open the live URL and confirm your brand rules held.
Commit the passing version

A deploy ships whatever sits in your project folder at that moment. Committing first pins the exact version that cleared all three checks.

  • Switch back to the terminal you ran your checks in.
  • Record the passing version by running these commands:
git add .
git commit -m "Landing page passing all three brand checks"
  • Confirm nothing was left behind by running this command:
git status

Git reports a clean working tree. The version you are about to deploy is the version that passed.

Commit refused to go through?

Git needs a name and an email set before it will record a commit, so a first-ever commit on a fresh machine often stops here.

You may also be sitting in the wrong folder. Check that your terminal is inside the project directory that holds design.md.

Why won't my commit go through?

Get the Vercel CLI ready

Vercel builds and hosts the page straight from your terminal. The CLI has to exist on your machine and be connected to your account before it can ship anything.

  • Check whether the CLI is already on your machine by running this command:
vercel --version

✔️ I see a version number

The CLI is installed and ready. Carry on to the login below.

ⓧ Command not found

The CLI ships as an npm package and needs Node.js 18 or newer.

  • Install the CLI globally by running this command:
npm install -g vercel
  • Confirm the install worked by running this command again:
vercel --version

A version number prints. If the install itself failed, npm is missing and you need Node.js on the machine first.

The next command is interactive. It asks how you want to log in, then hands off to your browser to confirm the account you already have.

  • Connect the CLI to your account by running this command:
vercel login

The terminal confirms which account you are logged in as once the browser hands control back.

Login never completed?

The browser tab has to finish loading before the terminal moves on, so a blocked pop-up or a closed tab leaves the command waiting.

If your browser was signed into a different account, the CLI links to that one instead of the account you meant to use.

My Vercel login is stuck, what should I check?

Deploy the page and open the live URL

Your checks proved the rules hold in the build sitting on your laptop. A deploy rebuilds the page on someone else's machine, so it tests the rules a second time.

The first run asks a few setup questions, like which account to deploy under and which folder holds the project. Accept the suggested answers unless you have a reason not to.

Before you run this, do you think the live page will come back branded or drop to the generic look from Step 1? Make your guess first.

  • Deploy the passing version by running this command:
vercel deploy --prod

What does this command do?

  • vercel deploy uploads your project folder and builds it on Vercel's side.
  • --prod sends that build to your production URL instead of a temporary preview one.
  • The deployment URL prints in the terminal once the build finishes.
  • Copy the deployment URL the CLI printed: your live deployment URL.
  • Open your live deployment URL in your browser.

The live page carries the same colours, type scale and spacing your checks passed on. Your brand rules travelled with the page because the agent wrote them into the code itself.

  • Check the live page against each of the three rules in design.md, one rule at a time.

Deploy stopped before it printed a URL?

The command has to run from the folder that holds your project files. Running it one level up gives Vercel nothing to build.

A build can also fail on something that only exists on your laptop, like a dependency you installed but never committed.

Help me read my failed deploy output.

Secret mission

Prove Your Rules Hold on a Second Page

Your three checks pass on one landing page. That page is also the only page your rules have ever seen. Point the same design.md at a brand new pricing page and find out whether you wrote brand rules or page rules.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. Everything you made lives in your repo or on your hosting platform's free tier, so nothing keeps charging you after today.

Resources you used:

  • Your landing page deployed to your hosting platform, live at a public URL.
  • Your local Git repository holding design.md and checks/check_brand.
  • The two comparison screenshots, screenshots/generic.png and screenshots/branded.png.

Keep everything running

No action needed. Choose this if you're still actively building on the page or want the live URL to stay shareable.

  • Leave your deployment live at its public URL.
  • Keep design.md in your repo root so your next project starts on-brand.
  • Keep checks/check_brand so you can rerun the three checks after any future edit.

Your coding agent CLI stays installed and signed in, because you had it before this project started.

Pause - I'll come back to this later

Shut down running processes to free up memory, and keep every file you wrote. Choose this if you want to pick the page back up later.

  • Press Ctrl+C in any terminal still running a local preview of your landing page.
  • End your coding agent CLI session so it stops holding your repo in context.
  • Leave design.md, checks/check_brand and both screenshots untouched in your repo.

Want the page offline while you're away?

Follow the Delete tab's deployment steps only. Your repo, design.md and your checks all stay on your machine.

Delete - I don't want to use this again

Remove all project resources and start fresh. Work through the deployment first, then the local folder.

Save design.md before you delete

Your design.md and checks/check_brand are the parts that carry into your next project.

Copy both somewhere outside your project folder before you run the delete command below.

  • Open your hosting platform's dashboard in your browser.
  • Select the landing page project you deployed.
  • Open that project's settings page.
  • Use the platform's delete option for the project, which also removes its public URL.
  • Reload the live URL in your browser.

The page no longer loads. You get your platform's not-found page instead of your branded landing page.

  • Delete your project folder on macOS or Linux by running this command:
rm -rf [[PROJECT_FOLDER_PATH="path to your project folder"]]
  • Delete your project folder on Windows by running this command:
rmdir /s /q [[PROJECT_FOLDER_PATH="path to your project folder"]]
  • Confirm the folder is gone by running ls in the folder that used to contain it.

Your project folder no longer appears in the listing, along with the screenshots and checks inside it.

That's a Wrap!

That's a Wrap

Nice work! You've turned your brand from a vibe into a spec that a coding agent has to follow, and you've got a live URL to prove it.

You've learned how to:

  • Write a design.md that holds your colours, type scale and spacing steps as values a coding agent can actually act on.
  • Prove the file changed the output by running the same prompt twice and putting the generic and branded screenshots side by side.
  • Turn your rules into mechanical checks that read the built page, then rewrite the vague rule the failing check exposed until all three pass.
  • Secret Mission: you pushed the setup further with an optional challenge built on top of your passing checks.

Ready to quiz yourself?