GEO Identity Drift: When Your llms.txt, Schema, and Homepage Tell AI Three Different Stories
Ask an AI engine "what is Stackbilder" last week and you'd get one of three different answers — depending on which file it happened to read. Our homepage said we ship production AI image generation. Our llms.txt said we were a "production hardening layer for AI-generated software." Our llms-full.txt said we were an "AI-assisted Cloudflare edge development platform."
All three were on the same domain, published by us, at the same time. We found this during a routine SEO/GEO audit of stackbilder.com, and fixed it the same afternoon. This post is the audit method, the failure mode, and why we think GEO identity drift is the new positioning bug most AI-crawled sites are shipping right now.
The GEO corpus: what generative engines actually read
Generative engine optimization (GEO) is search engine optimization for the machines that answer questions instead of listing links. ChatGPT, Claude, Perplexity, and Google's AI features don't rank your page — they read your site as a corpus and synthesize an answer about you.
That corpus is bigger than your HTML. For a typical site it includes:
- llms.txt and llms-full.txt — the emerging convention for handing LLMs a curated summary of what your site is
- robots.txt AI-crawler grants — explicit
User-agententries for GPTBot, ClaudeBot, PerplexityBot, Google-Extended, CCBot - JSON-LD structured data — your schema.org
OrganizationandWebSitenodes, plus any standalone schema endpoints - Server-rendered page content — titles, meta descriptions, body copy that crawlers get without executing JavaScript
We had all of it. Explicit AI-crawler allowances, both llms files, a schema map, full SSR. The plumbing was ahead of most sites. The problem was that the content flowing through it disagreed with itself.
And this channel is no longer theoretical. The same week we ran the audit, our analytics logged a session from chatgpt.com tagged ai-assistant — an AI engine sent us a visitor. We've written before about how agents discover your platform through ARD and MCP registries; the consumer-AI referral channel works the same way, and it reads the same corpus.
How llms.txt drift happens: repositioning ships to HTML first
Nobody wrote three identities on purpose. They accumulated.
Stackbilder started as a governed-scaffold product — threat models, ADRs, test plans for AI-generated codebases. When we repositioned around img-forge, our headless image generation API, we did what every team does: we updated the homepage. New hero, new title tag, new meta description, new OG tags.
The HTML got the new story. The GEO corpus kept the old ones:
$ curl -s stackbilder.com | grep -o '<title>[^<]*'
<title>Stackbilder — Ship image assets like you ship code
$ curl -s stackbilder.com/llms.txt | sed -n '3p'
> Production hardening layer for AI-generated software — governed
scaffolds, threat models, ADRs, and test plans for Cloudflare Workers.
$ curl -s stackbilder.com/llms-full.txt | sed -n '3p'
> stackbilder.com — AI-assisted Cloudflare edge development platform
Three files, three companies.
The mechanism is obvious in hindsight. Meta tags live in the page template, so they ride along with every redesign. llms.txt is a static route somebody wrote once. Schema JSON endpoints are another static route somebody wrote earlier. None of them are in the template path, so none of them update when the story changes. The files AI engines weight most heavily are the files with the slowest refresh cycle.
Classic SEO had a version of this — stale meta descriptions, outdated schema. But a search engine showing a stale snippet costs you a click. A generative engine synthesizing your identity from contradictory sources costs you the answer itself. When the corpus disagrees, the model picks one story, blends them into mush, or hedges. All three outcomes are worse than any single consistent story.
The audit also surfaced two structural bugs in the same family: our homepage @graph contained two WebSite nodes with different descriptions — the identity split reproduced inside a single page — and a SearchAction whose target URL was disallowed in robots.txt, meaning we were advertising an action to crawlers that crawlers were forbidden to verify.
The fix: one canonical sentence, enforced everywhere
The repair took two commits. The method matters more than the diff.
1. Write one canonical identity line. Ours is the homepage meta description, verbatim: "img-forge: production AI image generation for agents, apps, and pipelines — 11 models, one endpoint, flat credits, REST + MCP. Plus governed code scaffolds in every plan." One sentence, primary product first, secondary product named, no adjectives doing load-bearing work.
2. Grep for every surface that states an identity. For us that was seven files: the homepage meta, the llms.txt route, the llms-full.txt route, the Organization and WebSite JSON-LD nodes, two standalone schema endpoints, and the site-wide fallback meta description. Your list will differ. The grep is the audit.
3. Paste the canonical line into all of them. Verbatim where possible. Consistent phrasing across sources is itself a GEO signal — engines corroborate claims across documents, and identical strings corroborate perfectly.
4. Delete what crawlers can't verify. The duplicate WebSite node went. The robots-blocked SearchAction went. If a crawler can't confirm a structured-data claim, the claim is dead weight at best and a trust discount at worst.
5. Keep product-scoped pages product-scoped. We deliberately did not rewrite our scaffold-product landing pages to be about img-forge. A page targeting "backstage alternative" should keep saying what the scaffolder does — that's product copy, not identity copy. Drift is only a bug at the identity layer: the files that claim to say what the company is.
We've failed in public before by automating content without checking what it claimed, so the honest version of step 3 is: the fix is currently enforced by discipline, not tooling. The durable version is generating llms.txt and schema from the same source of truth as the page template, so the next repositioning physically cannot fork. That's on our list.
What Search Console says about where GEO traffic actually starts
The same audit gave us fresh Google Search Console data, and it reframed our whole organic picture.
Our product domain is fully indexed and earned 40 impressions in 28 days — effectively invisible, as we documented in Fully Indexed, Zero Organic Clicks. But the query-level data showed where the visibility actually lives: this blog. Niche agentic posts rank in the top 10 — the ARD/MCP piece at position 8, a scaffold case study at position 1, a local-LLM-routing post at position 2. Our img-forge quickstart is the single highest-impression page in the property. And that "backstage alternative" landing page is registering for its target query at position 39 — page four, but on the board.
Three standalone conclusions from that:
Search engines trust specific technical content from small domains long before they trust commercial pages. Our comparison and landing pages have well-written metadata and zero visibility. Our posts about ARD registries and inference routing rank top-10. Authority flows to whoever answers a narrow question completely.
Keyword-targeted pages register in Search Console before they rank. Position 39 with zero clicks looks like failure; it's actually the earliest visible stage of a working bet. The move is internal links from the pages that already rank, not a rewrite.
Your blog is the authority engine; your GEO corpus is the identity engine. The blog earns the trust. llms.txt and schema spend it — they're what the engine reads when it decides how to describe you. Getting the second half wrong wastes the first.
We ship img-forge — production AI image generation for agents, apps, and pipelines, with REST and MCP interfaces — and governed code scaffolds at stackbilder.com. Our GEO corpus lives at stackbilder.com/llms.txt if you want to see the fixed version, or steal the format.
Part 2: Your llms.txt Is Perfect and AI Agents Still Can't Reach You: The Transport Layer of GEO — the day after this post went up, we failed our own audit again, one layer down.