Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/aio-surfaces / aio_surfaces/config.py |
| Date | Not specified in source |
| Repository | Janady13/aio-surfaces |
| Revision | 4d0ef73ec42f209ff4947b559228f1884121ff8f |
| Branch | main |
| Path or archive member | aio_surfaces/config.py |
| Original SHA-256 | 7a7927fa85bf45eaf6fedec235c7217a511db9468fc95388aa4581202acb5867 |
| Git blob SHA | a9e78a0dbb19625bc5b444eba3ae4a50705d72c7 |
| Reading-copy SHA-256 | 7a7927fa85bf45eaf6fedec235c7217a511db9468fc95388aa4581202acb5867 |
Recovered source transcript
Download complete source text ↓118 lines · 3.6 KB
"""Typed site config. The single source of truth for every surface
this package generates. Load from YAML/JSON or build in code.
"""
from __future__ import annotations
from dataclasses import dataclass, field, asdict
from typing import Any
@dataclass
class Service:
"""One service pillar — appears in llms.txt + aeo.json."""
name: str
summary: str
url: str
price: str | None = None
@dataclass
class Fact:
"""One declarative atomic fact (the unit of AI citation).
Keep `answer` under 500 chars and use [subject][verb][object] sentence
structure. AI engines cite spans, not paragraphs, so density of clean
factual sentences correlates directly with citation rate.
"""
id: str
question: str
answer: str
def __post_init__(self) -> None:
if len(self.answer) > 1000:
raise ValueError(
f"Fact {self.id!r}: answer is {len(self.answer)} chars. "
"Aim for < 500 chars per atomic fact. AI citation rate drops "
"sharply above 500."
)
@dataclass
class SiteConfig:
"""Everything aio-surfaces needs to render the four surfaces.
Required:
site_name, site_url, tagline, description, services, facts
Optional verification graph (strongly recommended for AI citation):
legal_name, ein, uei, naics, orcid, kg_mid, gbp_cid, same_as,
veteran, has_credential
"""
# Core identity
site_name: str
site_url: str # canonical, e.g. "https://example.com"
tagline: str
description: str # ~200 chars
# Content
services: list[Service] = field(default_factory=list)
facts: list[Fact] = field(default_factory=list)
# Provenance / identity (Schema.org Organization)
legal_name: str | None = None
founding_date: str | None = None
founder_name: str | None = None
founder_url: str | None = None
address_street: str | None = None
address_locality: str | None = None
address_region: str | None = None
address_postal_code: str | None = None
address_country: str = "US"
telephone: str | None = None
email: str | None = None
# Verifiable identifiers
ein: str | None = None # IRS EIN (e.g. "12-3456789")
uei: str | None = None # SAM.gov UEI (12 char alnum)
cage_code: str | None = None
naics: list[str] = field(default_factory=list)
orcid: str | None = None # Person ORCID iD
kg_mid: str | None = None # Google Knowledge Graph MID
gbp_cid: str | None = None # Google Business Profile CID
# Off-site verification (sameAs JSON-LD)
same_as: list[str] = field(default_factory=list)
# Person credentials
veteran_branch: str | None = None
veteran_subgroups: list[str] = field(default_factory=list)
# AI crawler policy (allowlist)
ai_bots: list[str] = field(default_factory=lambda: [
"GPTBot",
"OAI-SearchBot",
"ChatGPT-User",
"ClaudeBot",
"Claude-User",
"Claude-SearchBot",
"PerplexityBot",
"Perplexity-User",
"Google-Extended",
"Applebot-Extended",
"Amazonbot",
"Meta-ExternalAgent",
])
def to_dict(self) -> dict[str, Any]:
return asdict(self)
@classmethod
def from_dict(cls, data: dict[str, Any]) -> SiteConfig:
# Reconstitute Service/Fact dataclasses
services = [Service(**s) for s in data.pop("services", [])]
facts = [Fact(**f) for f in data.pop("facts", [])]
cfg = cls(**data)
cfg.services = services
cfg.facts = facts
return cfg