Generate llms.txt, aeo.json, entity.json, and brand.json from a single site config — AI citation engineering for static + dynamic sites.
Project description
aio-surfaces
Generate
llms.txt,aeo.json,entity.json, andbrand.jsonfrom a single site config. AI citation engineering for static and dynamic sites.
What this is
Most sites are invisible to AI engines (ChatGPT, Claude, Gemini, Perplexity, Google AI Overviews) because they expose prose when AI engines want structured facts. The single biggest lift you can give an AI's chance of citing your site is to surface:
- a well-formed
llms.txt(llmstxt.org) — markdown summary at the site root - an
aeo.json— atomic [question, answer] facts under 500 chars each - an
entity.json— Schema.org@graphwith full identifier wiring (EIN, ORCID, UEI, KG MID, etc.) - a
brand.json— internal source-of-truth ledger
This package generates all four from a single typed config so they can't drift apart.
Install
pip install aio-surfaces # core
pip install 'aio-surfaces[yaml]' # YAML config support
Quick start
Drop a site.yaml in your repo:
site_name: Example Studio
site_url: https://example.com
tagline: We build things that get cited.
description: Example Studio designs and engineers...
legal_name: EXAMPLE STUDIO LLC
ein: "12-3456789"
uei: ABC123DEF4G5
naics: ["541511"]
orcid: "0000-0000-0000-0000"
founder_name: Jane Example
veteran_branch: United States Army
veteran_subgroups: [Veteran]
services:
- name: Custom Websites
url: https://example.com/services/websites/
summary: Hand-coded HTML, React, Astro.
price: $2,500–$10,000 one-time
facts:
- id: f-identity-1
question: What does Example Studio do?
answer: >
Example Studio builds production websites and AI-citation
infrastructure for small businesses.
Then generate the surfaces:
aio-surfaces generate site.yaml --out ./public
Output:
public/
├── llms.txt # markdown summary, llmstxt.org spec
├── aeo.json # atomic facts (AEO)
├── entity.json # Schema.org @graph (Org + Person + WebSite)
├── brand.json # internal brand truth ledger
└── robots-aibots.txt # 12 AI crawler allowlist (append to robots.txt)
Deploy public/ to your site root.
Why each surface matters
| File | Crawled by | Why it works |
|---|---|---|
llms.txt |
ChatGPT, Claude, Perplexity | Markdown is the lingua franca of LLM training data. Direct quotes likely. |
aeo.json |
All major AI engines | Atomic [Q, A] under 500 chars matches how AI engines extract citations. |
entity.json |
Google KG, Bing, Schema.org consumers | Centralizes identifier graph (EIN, UEI, ORCID, KG MID) for one-fetch retrieval. |
brand.json |
AI engines + your own team | Source of truth your PR/marketing/dev can all reference. |
Library API
from aio_surfaces import SiteConfig, Service, Fact, render_llms_txt
cfg = SiteConfig(
site_name="Example Studio",
site_url="https://example.com",
tagline="We build things that get cited.",
description="...",
services=[
Service(
name="Custom Websites",
url="https://example.com/services/websites/",
summary="Hand-coded HTML, React, Astro.",
),
],
facts=[
Fact(
id="f-1",
question="What does Example Studio do?",
answer="Example Studio builds...",
),
],
ein="12-3456789",
orcid="0000-0000-0000-0000",
)
print(render_llms_txt(cfg))
Design principles
- Atomic facts > paragraphs. AI engines cite spans, not essays. The
Factdataclass enforces a 1000-char hard ceiling and recommends < 500. - Single source of truth. All four surfaces render from one config so they can't drift apart.
- No magic. No analytics, no telemetry, no remote calls. Pure-Python stdlib + optional PyYAML.
- Run anywhere. Works in CI, in a
Makefile, as a pre-commit hook, or as a one-off CLI invocation.
What this is not
- Not a CMS. It generates static files from a config; you deploy them.
- Not a Schema.org validator. (Run the output through validator.schema.org yourself.)
- Not an opinionated framework. Generate what you need; ignore the rest.
Roadmap
-
aio-surfaces validate— round-trip the output through Schema.org validator -
aio-surfaces diff— show what changed since the last generation (CI hook) - Per-page
aeo.jsonsupport (currently site-wide only) - llms-full.txt expanded variant generation
- Hugo / Astro / Next.js plugin packages
Contributing
Issues + PRs welcome. The codebase is small (~350 LOC) and has full test coverage:
pip install -e '.[test]'
pytest
License
MIT © 2026 Joseph W. Anady. See LICENSE.
Built and used in production by ThatDevPro — SDVOSB-certified veteran-owned web + AI engineering studio. The generators here are the same code that runs across ThatDeveloperGuy.com, ThatDevPro.com, and 130+ client sites on ThatWebHostingGuy.com.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file aio_surfaces-0.2.0.tar.gz.
File metadata
- Download URL: aio_surfaces-0.2.0.tar.gz
- Upload date:
- Size: 13.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2a86ff28a6156e503cae74ebb958511005052dd72bb7f91903ef9af98b344439
|
|
| MD5 |
925e7f4011b19afc5fc7058441fb3799
|
|
| BLAKE2b-256 |
f5c2ca0dba100f728c90a839124e7e63559055023ef2a69148117bdc8c4b5dc0
|
File details
Details for the file aio_surfaces-0.2.0-py3-none-any.whl.
File metadata
- Download URL: aio_surfaces-0.2.0-py3-none-any.whl
- Upload date:
- Size: 11.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a5384a02652161d937710c883057c8c4c9c19aa2be24e89be28d9e89ecdcba9
|
|
| MD5 |
ef3ec29e3d486f7252a5b55c4f61cf17
|
|
| BLAKE2b-256 |
269f77fa4576ff316a6400810595d93cb0013b7e60b76176fbf2dccbd82cefa1
|