Until this week, every Croatian post on this blog told search engines it was written in English. All 63 of them. The lang attribute came from a single setting in the theme config, and it said en for every page.
That was one of the findings from a pass I ran over the whole site with Claude Code. The goal had three names. SEO is the familiar one, for search engines. AEO, answer engine optimization, is for tools that answer a question directly. GEO, generative engine optimization, is for AI models that quote and cite sources. In practice they ask for the same thing: each page has to make sense as a short extract and still be worth reading in full. People are still the audience I write for. Many of them will now arrive through an AI answer or a citation.
Look first, then change
My prompt asked Claude Code to inspect what the AstroPaper theme already did before touching anything. That saved work. The theme already generated a sitemap, an RSS feed, canonical URLs and Open Graph tags. It also added structured data, the JSON-LD block search engines read to understand a page, but it put the same BlogPosting block on every page. On the homepage, the publication date came out as the word “undefined”.
What was missing: the right language on each page, a description of the site and its author as WebSite and Person, and any file written for AI tools.
One field, four jobs
The core idea was to keep one text per post. The description field in the frontmatter now feeds the meta description, the summary visible under each title, the structured data and llms.txt. One text, nothing to keep in sync.
The visible summary sits below the date, in a box labelled “In short” on English posts and “Ukratko” on Croatian ones. Each label is one line in the config.
llms.txt is a proposed convention: a plain Markdown file at the site root that tells language models what a site is and where its content lives. Mine is generated at build time from the posts, so a new post appears in it without any extra work.
A post now shows “Updated” only when I change its content, not when a tool touches its metadata. None of the 90 posts got a new date from this pass.
Rewriting 84 descriptions
I had never noticed how alike my descriptions were until the audit counted them: 30 of the Croatian ones started with the same word, “Pregled” (overview). Several English posts I wrote for the Memgraph blog opened with “A comprehensive guide to” or “Learn how to”. A few posts from this year read like teasers and never named their subject.
The rule for the rewrite: name the subject in the first sentence and put the main point in the first 160 characters, because that is where search results cut off. One before and after:
A commit showed an email address I never typed. Turns out git is quite resourceful when you leave it to its own devices.
When user.email is not set, git builds an address from your login name and hostname and puts it in your commits. Two config lines fix it, but commits you already pushed keep the made-up address.
The first one is the better teaser. The second one survives being quoted out of context.
In the end, 84 of 90 posts got a new description, 61 of them in Croatian. Six already did the job and stayed as they were.
It asked before it assumed
What I appreciated most were the questions. Before writing any code, Claude Code wanted to know where the modified date should come from, whether the old WordPress addresses needed redirects, which URL should count as the original for posts first published on the Memgraph and Docker blogs, and how far “never mix languages on one page” should go. Some answers were obvious to me and not to it. A few I had not thought about.
It also tested instead of guessing. The repository has a CI pipeline, automatic checks that run on every pull request, and its format check had been failing on main without anyone noticing, because this was the first pull request the site ever had. Running Prettier, the code formatter, on all posts would have fixed it. Before recommending that, Claude Code built the site twice, formatted and unformatted, and compared all 232 pages. Two posts would have had their code examples rewritten: single quotes turned into double quotes in a Docker Compose file, and a semicolon added to another sample. So the posts stay out of the formatter, and the code I published stays the code I published.
What stayed with me
The notes that say where an archive post was first published moved into the header, in a smaller font. Croatian pages lost their English copy of that note. 36 Croatian titles traded their dashes for a colon. None of that is a technical decision. I made those calls, and the tool made them cheap to try.
The site reads the same to a person. It now also tells a machine, in the right language, what each page is about.