AI-built product2026Live
Moduly Homes: an AI-built catalog that has to prove its numbers
A live comparator of prefab and modular homes in Spain, built and run with Claude Code and a set of versioned agents. Generating pages was the easy part. The work was making every agent show where each figure came from.
Built and operated with AI agents, under human review
- Role
- Sole builder: product, data and AI operations
- Timeline
- July 2026 to today
- Stack
- Next.js 15, React 19, TypeScript, SQLite, Node
- AI
- Claude Code, Claude agents, OpenAI Codex
- Scope
- 1,137 models, 149 makers, 91 comparison pages
- Claude Code
- AI agents
- Prompt engineering
- LLM evaluation
- Data quality
- Web scraping
- Next.js
- SEO

- Problem
- Prefab home prices and specs in Spain sit on 149 manufacturer sites, each counting its own way. A comparator with wrong numbers is worse than none.
- Approach
- Claude Code as the engineering team, versioned agents for scraping and enrichment, and a verification layer: closed vocabularies, batch audits tested with planted controls, self-testing checks and my approval before production.
- Outcome
- Live since July 2026 with 1,137 models. Enriched records with source citations went from 5 to 277 in eight days. Google sends almost no one; ChatGPT sends twelve times more.
- commits co-authored by Claude Code
- 355/359
- 7 Jul – 10 Sep 2026
- models from 149 manufacturers
- 1,137
- live site, 18 Sep 2026
- guardians that must prove they can fail
- 48
- 18 Sep 2026
- enriched records with source citations
- 5 → 277
- 10 → 18 Sep 2026
Git history, the live home page, the project’s check scripts and its enrichment files (831 records on 10 Sep, 844 on 18 Sep).
A comparator is only as useful as its numbers
Moduly Homes is an independent comparator of prefab and modular homes in Spain. It does not sell houses: it gathers models, prices and specs from makers’ sites, links each figure to its source and puts buyers in touch with makers.
Every maker publishes differently. A “from” price may be a kit or a turnkey house, a floor area may include the porch, and a page title can quote a different price from the cart. An agent that fills gaps with plausible values builds exactly the page nobody should trust.
So agent output is untrusted until checked, an empty field beats a guessed one, and every check must prove it can fail.
Every figure passes six gates before it is published
Agents sit inside a deterministic pipeline, not at the end of it.
01
Sources
203 seeds with an approval state
- rate limit per domain
- source URL on every price
02
Extractors
Structured data first
- 70 per-domain profiles
- approved after a dry run
03
Enrichment agent
Prompt v30, in batches
- pages, PDFs, configurators
- a source per figure
04
Lint and audit
Before anything is applied
- typed answer to each warning
- tested with planted controls
05
Guardians
48 self-testing checks
- sitemap and noindex agree
- cited URLs re-checked
06
Gated deploy
My approval
- start-up and disk checks
- one restart per hour
Counts as of 18 Sep 2026.
What the agents produce, as a buyer sees it


Left: what a price includes; when the maker is silent, the page says so and shows how often the rest of the catalog charges that item separately. Right: room areas read from the maker’s plans, drawn only when the whole house adds up. Live site, 18 Sep 2026.
The agents do the work; I decide what ships
Claude Code co-authored 355 of 359 commits. The recurring jobs split like this.
| Task | What the AI did | What I decided | Guardrail |
|---|---|---|---|
| Application code | Wrote the app, the scrapers and the checks. | Set priorities; decide what ships. | Strict TypeScript and 24 build checks; a red check stops the build. |
| A new maker’s site | Maps where each figure lives, with a second spot to cross-check the price. | Approve the profile after its dry run. | Born “proposed”; a promoter script measures it and hunts for page elements that lie. |
| Enriching a model | Reads pages, PDFs and configurator code; returns specs, a scoped price and a source per figure. | Spot-check live pages; define what the auditor must catch. | Typed answer to every warning and writes to one folder only. The audit was tested with planted known-good records. |
| Categories | Suggests 4 to 8 per model. | Curate in a private console; my edits win. | Closed list of 24 slugs and 83 spec keys, generated from code. Free-form keys had reached 378. |
| Buyer enquiries | Drafts each reply. | Read, edit and send every email. | Drafts only; the server rejects a maker email carrying the buyer’s personal data. |
| Traffic diagnosis | Codex audits read-only, Claude re-measures, 15 agents research in parallel. | Decide which hypotheses stand. | Every claim needs a measurement and a date; TempoParking is the control group. |
| Deploys | Runs the deploy script. | Approve every production restart. | Stops on a failed start-up test, low disk or a restart in the last hour. |
- Task
- Application code
- What the AI did
- Wrote the app, the scrapers and the checks.
- What I decided
- Set priorities; decide what ships.
- Guardrail
- Strict TypeScript and 24 build checks; a red check stops the build.
- Task
- A new maker’s site
- What the AI did
- Maps where each figure lives, with a second spot to cross-check the price.
- What I decided
- Approve the profile after its dry run.
- Guardrail
- Born “proposed”; a promoter script measures it and hunts for page elements that lie.
- Task
- Enriching a model
- What the AI did
- Reads pages, PDFs and configurator code; returns specs, a scoped price and a source per figure.
- What I decided
- Spot-check live pages; define what the auditor must catch.
- Guardrail
- Typed answer to every warning and writes to one folder only. The audit was tested with planted known-good records.
- Task
- Categories
- What the AI did
- Suggests 4 to 8 per model.
- What I decided
- Curate in a private console; my edits win.
- Guardrail
- Closed list of 24 slugs and 83 spec keys, generated from code. Free-form keys had reached 378.
- Task
- Buyer enquiries
- What the AI did
- Drafts each reply.
- What I decided
- Read, edit and send every email.
- Guardrail
- Drafts only; the server rejects a maker email carrying the buyer’s personal data.
- Task
- Traffic diagnosis
- What the AI did
- Codex audits read-only, Claude re-measures, 15 agents research in parallel.
- What I decided
- Decide which hypotheses stand.
- Guardrail
- Every claim needs a measurement and a date; TempoParking is the control group.
- Task
- Deploys
- What the AI did
- Runs the deploy script.
- What I decided
- Approve every production restart.
- Guardrail
- Stops on a failed start-up test, low disk or a restart in the last hour.
Check counts as of 18 Sep 2026.
A scraper profile must name the parts of a page that lie
{
"profile_version": "v2",
"_estado": "propuesto", // proposed: not binding until measured and approved
"_revisar_el": "2026-12-10", // every claim carries a review date
"campos": {
"precio": {
"principal": { "capa": "dom_visible", "selector": ".product-price[data-price]" },
"contraste": { "capa": "data_attr", "selector": "#toWishlist[data-price]" },
"si_discrepan": "gana_principal", // closed list, no default
"PROHIBIDO": [{
"capa": "head_title",
"por_que": "the <title> shows exactly 70% of the visible price",
"casos": 7
}]
}
},
"_acierto": null // filled in by the promoter script, never by the agent
}Profile format from the extractor agent’s prompt, comments translated. A prohibition binds as soon as it is written.
Rule 0: fix a defect where it is born
The first section of the instructions Claude reads in this repository. A wrong record is a sample of a mechanism.
Measure the mechanism, not the case
3 → 17 → 131Reported: 3 broken URLs. Retired pages missing a redirect: 17. The whole mechanism: 131.
Fix what is already live
Published damage does not heal itself.
Find the origin at file and line
A suspicion is not an origin.
Close the door
If nothing remembers the previous state, build that memory.
Add a guardian that can fail
Its
:perturbarmode breaks what it watches and must turn red. One checker once passed 88 records with a broken price function.Verify live and keep the lesson
Check the real URL past the cache, then add a one-line lesson to the agents’ prompts.
What the agents taught me about agents
Each lesson is a one-line “pill” in the repository, quoted in the prompts and in the guardians that enforce it.
01
A field, not a paragraph
An agent saw a maker’s page title advertise a lower price than its cart, and said so in prose. Nothing read it, and the wrong price stayed live.
812 of 831 enriched records kept their flags only in prose (10 Sep).
02
Evidence from the audited page verifies nothing
A batch of 41 price corrections used each page’s own title as proof. The title is marketing, written by the same hand as the price.
14 of the 41 (34%) were still wrong.
03
An objection beats an obedient mistake
The brief is a hypothesis. One agent found a certificate the brief said did not exist; five pages had published the false claim.
One batch: 33 objections, 4 of them real bugs in the pipeline code.
04
Brief a swarm like a colleague
A 15-agent research swarm went out without the control group or the list of ruled-out causes, and rediscovered dead hypotheses.
Four agents read a Google CAPTCHA as evidence against the domain.
One model audited the diagnosis; another audited the audit
I asked OpenAI Codex for a read-only critical review of my diagnosis of the July traffic drop, written with Claude. Then Claude re-ran every measurement.
| Claim in the first diagnosis | Codex | Claude’s re-check | Status |
|---|---|---|---|
| No deploy on 20 Jul, so we did not cause it | A deploy went out on 19 Jul, and Search Console days run on Pacific time | Confirmed: its own error | Withdrawn |
| Outside our brand, Google sends no one | Only 4 of 20 clicks map to a visible query | Confirmed | Brand split unknown |
| Only the long tail vanished | Rankings fell on comparable page–query pairs | 18 of 25 pairs lost more than 5 positions | Real ranking loss |
| Google stopped rendering JavaScript | Crawl-stats samples are not exhaustive | Confirmed | Withdrawn |
| Content quality is ruled out | A province page listed a maker that says it works elsewhere | 20 such pages; a two-line fix | Fixed |
Both reports dated 10 Sep 2026.
The review pushed back on Codex too
Codex made the mobile collapse (−95.3%, against −81.4% on desktop) its main lead. Split by page, it was a few brand searches of one to six a day. Neither Codex nor the first diagnosis noticed that the 21 Aug drop coincided with Google restoring Search Console data. And the crawl fell first: 9,262 Googlebot requests on 12 Jul, 34 on 20 Jul.
Offer Google less, and let the build enforce it
One module decides what each page type offers Google. The sitemap and the robots tag both read it, and the build fails if they disagree. Pages leave with noindex, follow, so they stay linked.
The sitemap went from 1,192 to 775 URLs on 9 Aug. On 1 Sep, 300 model pages that had never had an impression went to noindex, with 346 kept as a control. The quality score was audited too: “has a photo” carried 40% of its weight and correlated 0.02 with real quality.

The honest outcome: indexed, but barely shown
Search Console holds 66 days of history: 6,919 impressions and 80 clicks from 5 Jul to 8 Sep 2026. Impressions peaked at 666 on 13 Jul, fell to 113 on 20 Jul and have not recovered, although 957 of 984 sitemap URLs were indexed on 1 Sep.
My working hypothesis, not a proven cause: Google tried the site as an intermediary on makers’ own brand searches (76% of July’s queries named a maker) and withdrew it. Bing still ranks the same pages, and TempoParking, my other 2026 site, dipped and then grew.
Buyers still arrive, just not from Google. Of 32 enquiries between 10 Jul and 8 Sep, 7 came via ChatGPT and none via Google.
- sitemap URLs indexed
- 97%
- 957 of 984, 1 Sep
- impressions after 20 Jul
- −85%
- 10-day windows: 4,555 → 669
- Google clicks in 30 days
- 20
- 10 Aug – 8 Sep
- buyer enquiries in 2 months
- 32
- 7 via ChatGPT, 0 via Google
Search Console API and index report; the site’s own analytics, measured 10 Sep 2026.
ChatGPT sends twelve times more visitors than Google
| Category | Visits |
|---|---|
| ChatGPT | 365 visits |
| Bing, Yahoo, DuckDuckGo | 117 visits |
| 30 visits |
Visits by referrer, 30 days to 10 Sep 2026. Direct visits with no referrer (2,513) are not shown.
Source: Site analytics in production
Next case study
Estimating asking prices from 500+ listings collected with n8n
Related

Web product2026Live
TempoParking
A live directory of 15,000+ car parks in Spain, built and run with AI agents.
tempoparkings.comAI engineering
Teaching a debugging agent where to look first
An AI agent for parasitic-extraction debugging, built without a vector database: gated phases, hybrid lexical search, benchmarks and intent-routed playbooks.

Data engineering2025
House prices from scraped listings
An n8n scraper and a baseline price model for 500+ local housing listings.
Get in touch
Working on something similar? I am happy to compare notes.