How I built this site with an agent
I built my personal site with Claude in August 2026, and this is the pipeline I ran, stage by stage, in the order I ran it. Each stage is a decision you can copy. Follow them in the same order and you should be able to get a comparable result for your own site.
The order is the argument. Almost every mistake I made came from running a stage early, so the map below is the whole method in one picture: eight stages in three phases, read top to bottom. Phase one settles the visual language before a single page exists. Phase two builds the work with a critic inside the loop. Phase three lets a machine, not a model, decide whether it is finished. Every box is a link to its stage.
- Phase 1 · Settle the languagenothing is built yet
- Stage 1Brand first, page lastClaude Design
- Stage 2Design system, then skillSKILL.md
- Phase 2 · Build with a critic in the loopmake and check in the same pass
- Stage 3Builder and criticthe opening prompt
- Stage 4Fan out only where work is independentten pages, ten agents
- Stage 5A review loop you will usein-browser overlay
- Stage 6Batch the reviewone file per round
- Phase 3 · Prove it, then shipa machine decides, then the tooling goes
- Stage 7Judge with something mechanicaltwo servers, one read
- Stage 8Strip the tooling, then deployharden, then ship
Brand first, page last
I opened by asking for a page. I got two page designs back, and they were the wrong thing, because I had not decided anything they were meant to express. The correction is the single most useful move I made on this project:
Hmm, those designs did not do the trick and you went straight to the web draft. I
would like to first decide on a color palette, the font, design details, graphics,
etc. I am not an expert but I think you went too far. I do not need the page design
now, I need for it to appear naturally from all the previous design constraints. I
would much rather have a document, presentation canvas of ideas [...] where we can
define step by step and then we decide how the page looks like. So maybe include
all the information that we have talked about into some place where we both can
visit to remember the design and let's iterate.
Every prompt on this page is mine. They are reproduced as written apart from spelling and, in this first one, a few words tidied for clarity. Nothing in them has changed meaning.
What I was asking for was not a smaller design. It was a place to do the deciding. I wanted to work through everything that makes up a brand, in order, and end up holding every input the design system would later need, so that when I finally asked for that system I could get it in one pass and get exactly what I meant. A page is the last thing you should ask for, because a page is a conclusion. This document is where the premises go.
What to copy. Every move I made in that document was a rejection with a direction attached, never just “I don't like it”. Open any of the four to see what came back.
I replaced the palettes with two sampled from named paintings
Monet's Impression, Sunrise and A Path in the Garden, each with a calculated dark mode rather than an inverted one. Naming a painting gives a colour brief something a word like “calm” cannot: a fixed reference both of us can check against.
The measurement of how much of that is really in the painting is two figures down.
I replaced the typography twice, and the second time by period
First with a 1920s book face and a Spanish agitprop poster face. Then again with Fondamento and Brygada 1918, to test a calligraphic hand against a 1918 type revival. Asking by period and by artefact, rather than by adjective, is what made the options distinguishable.
| Pairing | What it was testing |
|---|---|
| Brygada 1918 + IBM Plex Sans | A full text family from a 1918 revival, with an engineered sans for labels |
| Fondamento + Spectral | A calligraphic hand carrying personality, a plain serif carrying the reading |
| Space Grotesk + Source Serif 4 | Geometric grotesque declaring, serif explaining. This is the pairing that won |
I pushed the graphic language to 1920s and 1940s print
What came back was a Constructivist monogram drawn from trademarks in my own reference sheets: a circle, a tilted band and a solid block, off-grid, used once per view. The second is the one that eventually became the favicon.
I asked for the image rule to be a printing process, not a filter
Photographs print as two misregistered ink plates, a sun plate and an ink plate offset from each other over the fog ground, with the register shift varying per image so no two look mechanically identical. That is a rule a stylesheet can implement and a person can check. “Make the photos feel handmade” is not.
By the end I had two favourites in every category and could not choose. The answer was not to rank them. It was to build two complete, internally coherent systems and compare them as wholes, because a palette you like in isolation can fight a headline face you also like in isolation.
A · The Press Room (not chosen)
B · The Harbour (chosen)
A palette described as “sampled from a painting” is a nice sentence, so it is worth checking. I loaded the painting into a canvas and, for each of the six colours, searched every pixel for the closest match by RGB distance. All six are genuinely in the painting, and the one that is furthest out is the one you would expect.
sky
mist
sun
fog
night
ink
#CB5633 and the
brand lifts it to #E0552C, which is the one deliberate exaggeration in
the system. Painting: Claude Monet, Impression, Sunrise, 1872, Musée
Marmottan Monet, public domain.
One more sheet came after those two, and it is out of order in every telling of this I have written since. Having built A and B, I still could not commit, so I asked for favicon candidates in Miró's vocabulary before locking either system. Twelve marks came back, each shown at 96px and again at 20px, and seeing the mark decided the system.
Design system, then skill
A specimen sheet is a picture. To be useful to an agent it has to become a directory of values. I locked the winning sheet, uploaded it, and wrote a brief that pinned every layer down before anything was generated.
| Layer | What I locked |
|---|---|
| Ground | Fog #DCE4E8, ink #2C3A47, mist #6D89A0 |
| Accent | Sun #E0552C, one per component, never two |
| Dark ground | Night #1E2B38, text in warm sky #E6CBB3, accent lifted to #DD4B1F |
| Type | Grotesk declares, serif explains, mono carries technical metadata |
| Structure | Alignment-driven, flush left, no boxes where whitespace will do, sharp corners, no shadows |
| Imagery | Two misregistered ink plates, register shift varying per image so no two look mechanical |
| Voice | Declarative, no first person, no hedging, no marketing adjectives. This field note is the one surface exempt from that rule, because a method is easier to follow in the first person. |
What came back was tokens/ as CSS custom properties, components for the
brand primitives, full-screen kits, guideline cards, the marks as SVG, and a readme that
states its own sources and flags where it departs from them.
The readme names the uploaded sheets as ground truth, states that no codebase or design file was supplied, and adds a tie-break rule: where the sheets and a published convention disagree, the sheets win. It then records the one deliberate difference, that the sheets carry a placeholder name while the components carry mine. A design system that writes down where it departed from its brief is doing the same job as a commit message.
I built the system in Claude Design,
and then did the step that makes it portable: I put a
SKILL.md
at its root, in the format Claude Code expects, so an agent in a different tool can pick
the brand up and apply it. Two separate surfaces, joined by one file. It is nine lines:
---
name: the-harbour-design
description: Use this skill to generate well-branded interfaces and assets for
The Harbour — the personal portfolio design system for Marcos Carlero — either
for production or throwaway prototypes/mocks/etc. Contains essential design
guidelines, colors, type, fonts, assets, and UI kit components for prototyping.
user-invocable: true
---
Read the README.md file within this skill, and explore the other available files.
If creating visual artifacts, copy assets out and create static HTML files for the
user to view. If working on production code, you can copy assets and read the rules
here to become an expert in designing with this brand.
Worth saying plainly, since you are reading it right now. The table above locks sharp corners, no shadows and a serif for body copy. The page around you has rounded corners, three tiers of shadow and no serif anywhere except the pull quotes. The Harbour governs my portfolio, which is the surface it was built for. This section is a different surface with a different job, and it keeps its own system. A design language that quietly spread to everything I own would be a failure of the stage above, not a success of it: the point of locking a system is knowing what it is for.
Builder and critic
My first real build prompt was not a request. It was a role brief with an execution plan, a named adversary and a stop condition. I have replaced the program names with the published aliases I use everywhere else, since the work is under an NDA.
It is one prompt, and it does three jobs. The colours below mark which sentences do which. Point at a part, or tap its card, to light up the lines it covers.
I want you to act as an autonomous engineering squad led by a Master Software
Architect. Your task is to build a highly interactive web portfolio that showcases
my professional projects with extreme rigor and polish [...]
The portfolio must allow users to explore my projects through exactly 3 layers of
deep abstraction, ensuring I showcase my technical depth without ever revealing
proprietary source code.
EXECUTION PLAN & AGENTIC LOOP:
Fan out specialized sub-agents to tackle each project and layer individually.
Crucially, instantiate a separate "Harsh Critic" sub-agent. You must /loop on
every single item, diagram, and textual explanation. The Harsh Critic must
meticulously check for hallucinations and enforce absolute technical rigor.
Don't stop until the Harsh Critic is utterly wowed by the truthfulness and
accuracy of the findings. The Critic should literally do a blind side-by-side
comparison of the sub-agents' output against industry-standard documentation
(e.g., Martin Fowler's architecture definitions, Gang of Four design patterns)
[...] If the Critic finds any flaws, lack of depth, or hallucinations, it must
reject the work and keep going.
Defines the exact deliverable, the audience and the absolute quality standard. It sets the persona the model adopts and the hard boundaries on content: which design system is mandatory, which topics are omitted, and here what may never appear at all, since the source material is under an NDA.
“Exactly 3 layers” does more than it looks. A countable constraint is checkable. “Deep” is not.
Part 2 The how execution architecture and workflowDictates how the model organises itself. It commands the fan-out, assigns distinct operational roles, and starts the autonomous loop by physically separating making the content from reviewing it. That separation is the evaluator-optimizer pattern, and it is why the critic cannot be argued with.
Stage four is the caveat: fan out across independent work, never across coupled work.
Part 3 The result exit condition and strict evaluationDefines when the loop may stop. It parameterises the independent evaluator and gives it an objective ground truth, the blind side-by-side comparison against an elite standard. That is what stops the model approving its own incomplete work.
This is the clause that makes the loop converge instead of just costing more.
A walkthrough of the whole pattern, by the person who named it, is on video.
Three subagents went out against three codebases inside the first minute. The shape is not mine. It is the pattern Matt Shumer named the Gauntlet Loop in July 2026, after using it to generate a browser first-person shooter from a single prompt, released as Claude of Duty.
The agent (not you!!) breaks the goal into parts, gives each part a specialist builder and a ruthless blind critic sub-agent, with a mandate to only pass if the generated artifact is better than some real-world equivalent.
The underlying idea is older, and reading it is worth more than copying the prompt. Anthropic's agent guidance describes an evaluator-optimizer workflow: one call generates, a separate call evaluates against explicit criteria and sends it back. A single agent asked to continue until its work is perfect is grading its own homework, and stops early. A critic with its own context cannot be argued into approving weak output, because it never saw the argument.
Building Effective Agents (Anthropic, December 2024) sets it out in one sentence: “In the evaluator-optimizer workflow, one LLM call generates a response while another provides evaluation and feedback in a loop.” It also names the condition under which the extra cost pays: “This workflow is particularly effective when we have clear evaluation criteria, and when iterative refinement provides measurable value.” Everything the “harsh critic” clause does is an application of that.
| What the prompt leans on | What it actually is |
|---|---|
| Subagents | The mechanism the critic depends on. Each one runs in its own context window with a custom system prompt, specific tool access, and independent permissions, which is precisely why it cannot be talked round. |
/loop |
A bundled skill rather than a built-in command. It runs a prompt repeatedly while the session stays open, which is what turns “keep going” into something that actually iterates. |
ultracode |
A setting that combines the highest reasoning effort with automatic workflow orchestration. Worth knowing what it is not: it runs an orchestration script in an isolated runtime, so it is not simply “more subagents in one turn”. |
The clause that does the real work
“Blind side-by-side comparison against industry-standard documentation” is the load-bearing sentence, and if you copy one line from that prompt, copy this one. An agent stops when it decides a task is done, and “until it is perfect” is a judgement it can make in its own favour. Naming an external artifact to be beaten replaces a judgement with a comparison.
It is also where the honest limit sits, and the author of the pattern is the one who documents it. Claude of Duty's own README reports that eleven adversarial critics scored the result 3.59, then 4.14, then 4.05, then 5.05 out of ten, and that in a blind A/B every critic in every round still picked the real game. Setting an external bar makes the loop converge. It does not make it win.
Fan out only where work is independent
The largest parallel run on this project was ten agents, one per long page, each applying Simplified Technical English to the prose. It worked, and it worked for a specific reason: no two of those pages share any prose. They share a stylesheet, a script and a prev/next chain, none of which the rewrite touched, so no agent could invalidate another one's work.
Two things made it safe rather than lucky.
- An extractor first, and then a correction to it. My immediate follow-up prompt was “It is really important not to change any quotes or diagrams so please could you revise the extractor you did to make sure no quotes or diagrams are passed to the text reviewer”. Canonical quotations are the evidence those pages rest on. A prose simplifier let loose on a quotation produces a paraphrase still attributed to its author, which is worse than a clumsy sentence.
- A critic agent per rewrite, not one at the end. I sent six further critic dispatches after the rewrites, each reading one or two pages against the original.
This is the correction to the prompt in stage three, and it comes from the author of that prompt. Claude of Duty's README reports that three rounds of six agents, each owning one directory, moved the score by +0.46 and left frame-ruining defects higher than they started, 60 to 47 to 66, because the systems those agents owned were coupled and they kept breaking each other's assumptions. One sequential pass with a single owner per coupled concern moved it +1.00 and cut defects from 66 to 26.
So: fan out across pages, chapters, independent components. Do not fan out across a layout, a palette and a type scale that all read the same tokens.
A review loop you will use
Two days in, I stopped asking for page changes and asked for a tool to request them with instead. This is the stage most people skip, and it paid for itself inside a week.
I would like to add some comments to the portfolio webpage you created like if it
was Claude design where I can click on html objects or create square objects and
write comments for you to edit. I need you to create the best system for us two.
It needs to be simple for me to select the correct elements in the web page or at
least to highlight the elements that I want altered and for you to understand
exactly in the code the request is [...] I would also like to be able to create
multiple requests in different parts of the app and only send them to you once I
want using a button or telling you in the chat to read some file, please choose best.
Describing a change in prose is expensive and ambiguous. “The third paragraph under the second heading, the one starting Two years, stated exactly” costs a lot of words and can still point at the wrong element. A click cannot. Select, write, and send the whole set at once.
The design decision that matters is anchoring. Each note records a text snippet as its primary locator, because a unique string finds a file and a line and survives the file being edited. The CSS selector is stored as a secondary hint and is deliberately not the thing relied on. Dragged regions store percentages against the nearest block ancestor, so they survive a resize, a zoom or a theme change.
Mine is about 600 lines of dependency-free JavaScript and it is not on this site, so
you cannot copy it from here. Ask your own agent to build one and hold it to three
things, which are the only parts that matter: a click selects an element; each note
stores a text snippet as its primary locator and the CSS selector only as a
fallback; and the notes leave as one markdown file rather than one message each.
Anything that does those three things will do. Gate it to localhost on
day one, not on the day you deploy.
The prompt that produced mine is at the top of this stage, with a copy button in its corner. Take it and hand it to your own agent, then expect to correct it: my next two messages were both bug reports about the drag-to-mark rectangle, which is the part that is fiddly to get right.
Batch the review
The tool is only half of it. The habit is the other half, and it is borrowed straight from code review: you do not comment on one line, wait for a push, then comment on the next. You read the whole thing, leave every comment, and submit once.
That is also the cheaper way to run it, which surprised me. Sending notes one at a time feels lighter and is not: each one is a separate turn, and each turn re-reads the page, the stylesheet and the context around the change before it can act. Ten notes sent singly pay that cost ten times, and by the tenth the agent has usually rewritten something it touched on the third. One batch is one prompt against one already-loaded context, and it lets the agent see that five of the eight requests are the same complaint. Batching saved me tokens and it saved me contradictions.
In practice that meant I could read a full page while the agent was working on something else, hand over the entire review, and move to the next page without stopping. A batch comes out as markdown and goes back in as the next prompt:
# Review requests (8)
### 1. I really do not like the em dashes, remove them an leave a text like this:
Ten concepts are each explained from their canonical source: Meyer, Fowler, the
Gang of Four, Nygard, Richardson, and the W3C. [...]
- **Type:** element
- **Element:** `p`
- **Find this text:** `Ten concepts, each explained from its canonical source — Meyer, Fowler,`
- **Selector:** `#main > section.hero:nth-of-type(1) > p:nth-of-type(1)`
### 5. I would like to change the text to this: Presentational components that
import a global store lose their presentational nature. [...]
- **Find this text:** `Presentational components that import a store are not presentational.`
- **Selector:** `#hard-lessons > div.cards.hard:nth-of-type(2) > a.card:nth-of-type(3) > p`
---
_Locate each item by the "Find this text" string; the selector is a fallback hint._
Five of those eight requests were the same complaint about em dashes. That is the real argument for batching: a defect that appears five times is one instruction, not five conversations.
Judge with something mechanical
After that rewrite I did not ask a model whether the prose had improved. I served the old version and the new version at the same time and read them against each other.
This is what “blind side-by-side comparison” has to mean to be worth anything. Without something outside the model deciding, a critic agent is an opinion with extra steps. The cheapest mechanical referees, in the order I reached for them: a second server on another port, a linter, the browser console, and the rendered page at a phone width.
Then stop
The other half of judging is knowing when to stop, and here the Gauntlet Loop's “do not stop until the critic is wowed” works against you. Most of my design passes ran through impeccable, whose documentation says it plainly:
Verify in bounded passes, not a loop, and the ceiling covers the whole cycle: screenshots, defect scans, micro-edits, and rebuilds alike. Build fully, inspect once with a batched round [...], fix everything it shows in one batch, confirm with at most one more round, and stop polishing.
The two are not in contradiction once you see what separates them. A loop with an external referee converges, because something outside the model decides. A loop with an internal referee and no external check does not converge, it just costs more. I ran the lifecycle as separate named passes rather than one instruction, and that separation is what made each pass reviewable.
| Pass | What it is for | What it produced here |
|---|---|---|
/impeccable init | Write the durable product record | Audiences, stack reasoning, the NDA constraints |
/impeccable critique | Design review by isolated agents | A scored report: 18 of 36, one P0, three P1 |
/impeccable audit | Code-level defects, not taste | Contrast failures and a broken document outline |
/impeccable polish | Fix what the audit found | One batch, then stop |
/impeccable harden | Make it safe to ship | Removed the review tool from the site |
I ran it as two isolated agents, a design review and a detector-and-browser evidence pass, and it came back with a per-heuristic table. No feedback on either primary control. No current-section state across a fourteen-screen document. Navigation deleted below 700px with no replacement. A term I had used six thousand pixels before I explained it.
Every one of those is a thing I would have defended if a model had simply told me the page was good. critique run 2026-08-12 · 18/36 · 1 P0 · 3 P1
Strip the tooling, then deploy
The review overlay that made this whole workflow possible is not on the deployed site. I
gated it to localhost as soon as the repository started deploying, and then
deleted it outright, 1,692 lines across both site trees, before the first public deploy.
A runtime host check is a control. Not shipping the authoring tool at all is the absence
of the risk.
I then ran a pre-deploy sweep as three agents, one doing a static scan, one probing the live site, one checking the CV for unintended metadata. It caught two things the rendered page could never have shown me:
.git/was being uploaded as a public static asset, so the whole commit history was reachable. My host uploads whatever sits in the assets directory; its own migration guide notes that the older Pages product used to exclude.gitautomatically and that Workers does not; the fix is an.assetsignorefile, which takes the same format as.gitignorebut is a separate mechanism from it. I confirmed the exposure in a live deploy log before fixing it.- The CV PDF carried AI-tooling strings in its metadata. That commit changed zero visible lines, which is exactly why reading the document would never have found it.
Both are the same mistake: what ships is the filesystem, not the repository, and not the rendered page.
Where it went wrong
Two failures worth more than the successes, because they are the ones that will happen to you too.
The agent edited code I had not asked it to touch
Dude, what are you doing, I haven't given you any permissions or clear request to
alter the code. If you have done any changes please revert them [...]
This is the failure mode that matters most, and it is not a code defect. An agent that widens its own scope produces a diff that no longer corresponds to a request, and an unreviewable diff is worse than no work at all. Say it once, plainly, and it holds.
Four rejected rounds before one landed
A late design job took five attempts. What made the fifth work was that the rejections stopped being about taste and started pointing at artifacts that already existed: “I prefer my main page circle bar and square favicon”, then “go back to the size it was before and check my harbour design”. Pointing at a thing beats describing a preference.
What the site looked like on the way
What transferred
Strip the tool names away and six things did the work. None of them are prompting tricks, which is rather the point.
| Practice | The engineering equivalent |
|---|---|
| A separate critic with its own context | You do not review your own pull request |
| An external artifact to be beaten | A test suite, not a careful reading |
| Batched review, submitted once | A pull request review, not a running commentary |
| Constraints written down before the work | An architecture decision record, written before the code rather than after it |
| Fan out only across independent work | Parallelise where there is no shared state |
| Tooling removed before the deploy | Build artifacts are not shipping artifacts |
The agent wrote nearly every line of markup on this site. It also widened its own scope
once without being asked, produced a design I rejected four times running, and would
have deployed a public .git directory if I had not asked for a sweep. The
output is exactly as bounded as the instructions and the review, which is the same
thing that is true of any engineer, and the same thing every page in this section says
about patterns: the name is not the implementation.
Canonical sources
- Anthropic: Building Effective Agents · December 2024. The evaluator-optimizer workflow in stage three, and the condition under which paying for a second call is worth it. Read this before copying anyone's prompt template.
- Matt Shumer: Claude of Duty · the artifact the Gauntlet Loop was named for. Its Honest assessment and Process note sections are the useful part: the scores, the blind A/B result, and the finding that parallel fan-out lost to sequential single-owner passes on coupled work.
- Matt Shumer: naming the Gauntlet Loop · July 2026, the source of the quotation in stage three. The repository above does not use the name, so this post is the citation for it.
- Claude Code: subagents · the separate context window that makes an independent critic possible rather than rhetorical.
- Claude Code: skills · the
SKILL.mdformat used in stage two to make a design system portable between tools. - pbakaus: impeccable · the design skill behind the five passes in stage seven, and the source of “verify in bounded passes, not a loop”.
- ASD-STE100: Simplified Technical English · the controlled language applied in stage four. Issue 9 is the current specification.
- Claude Design · where stages one and two happened, before any code existed.
- Cloudflare: ignoring assets · the
.assetsignorefile from stage eight, and why it is a separate mechanism from.gitignoredespite sharing its format.
