---
name: aeo
description: "Answer Engine Optimisation. Emits schema.org JSON-LD for typed graph entities, generates llms.txt + llms-full.txt for the site, and audits pages against eight AEO heuristics with one rewrite suggestion per fail. Writes :AEOAudit history nodes when audits are persisted."
tools:
  - name: aeo-emit-jsonld
    publicAllowlist: false
    adminAllowlist: true
  - name: aeo-write-llms-txt
    publicAllowlist: false
    adminAllowlist: true
  - name: aeo-audit-page
    publicAllowlist: false
    adminAllowlist: true
skills:
  - skills/structured-answer/SKILL.md
always: false
embed: false
metadata: {"platform":{}}
mcp:
  command: node
  args:
    - ${PLATFORM_ROOT}/lib/mcp-spawn-tee/dist/index.js
    - ${PLATFORM_ROOT}/plugins/aeo/mcp/dist/index.js
  env:
    MCP_SPAWN_TEE_NAME: aeo
    LOG_DIR: ${LOG_DIR}
    PLATFORM_ROOT: ${PLATFORM_ROOT}
    ACCOUNT_ID: ${ACCOUNT_ID}
    SESSION_ID: ${SESSION_ID}
    AGENT_SLUG: ${AGENT_SLUG}
mcp-manifest: auto
---

# AEO (Answer Engine Optimisation)

This plugin makes the platform's content legible to answer engines — Claude, ChatGPT, Perplexity, Google AI Overviews, Bing Copilot. Classical SEO ranks links; AEO shapes the page so the answer-engine extractor lifts the right answer.

## The three surfaces

1. **JSON-LD** (`aeo-emit-jsonld`). Every typed graph entity that backs a page can be projected to a `<script type="application/ld+json">` block. The mapper covers `Organization`, `LocalBusiness`, `Person`, `Service`, `Product`, `Article`, `FAQPage`, `RealEstateListing`, `Event`. Other labels fall through to `schema:Thing` and are flagged as a doc gap.

2. **llms.txt** (`aeo-write-llms-txt`). The site emits `/llms.txt` (index of pages, one link per line) and `/llms-full.txt` (concatenated full text). Format follows the current draft at `https://llmstxt.org/`. Source is `KnowledgeDocument` nodes with a `url` property. Pages without a `url` are skipped and counted in the response. Called with `siteDir` (an absolute path to an existing site root), the tool writes both files to disk and the response carries `writtenPaths`; called without it, the tool returns the file bodies inline for on-demand callers. The publish-site skill calls this with `siteDir` set to the freshly-published `<accountDir>/sites/<slug>/` on every publish, so the pair stays fresh as `KnowledgeDocument` nodes change.

3. **Audit** (`aeo-audit-page`). Run the eight-heuristic scorecard against a URL or raw HTML. Each heuristic returns pass / warn / fail with one rewrite suggestion per fail. Score is `100 * (passes + 0.5 * warns) / 8`. Pass `persist: true` with a `targetKnowledgeDocumentId` to record an `:AEOAudit` node linked back to the document.

## The eight heuristics

| Heuristic | Pass | Warn | Fail |
|---|---|---|---|
| `h1-present` | one `<h1>` | more than one | none |
| `jsonld-present` | one or more JSON-LD blocks, all parse | some parse | none, or all unparseable |
| `structured-answer` | first `<p>` after `<h1>` is ≤280 chars | first `<p>` is over 280 chars | no `<p>` after `<h1>` |
| `faq-section` | `FAQPage` JSON-LD on page | FAQ text but no JSON-LD | nothing FAQ-like |
| `meta-description` | 80–160 chars | present but outside range | absent |
| `canonical-url` | `<link rel="canonical">` present | — | absent |
| `og-tags` | `og:title` and `og:description` both set | — | one or both missing |
| `heading-hierarchy` | no level skips | — | h1→h3 or similar jump |

`structured-answer` is the highest-impact: answer engines lift the structured-answer span verbatim. A page can fail every other heuristic and still get cited if the first paragraph cleanly answers the question.

## Persistence model

The plugin only writes `:AEOAudit` nodes (when `persist: true`). It does not own the entities it reads — `KnowledgeDocument`, `Organization`, `Person`, etc. belong to the memory plugin. Edges written:

- `(:KnowledgeDocument)-[:HAS_AEO_AUDIT]->(:AEOAudit)`

The audit nodes carry `accountId`, `target` (URL or `(inline html)`), `score`, `heuristicsJson` (full result), `runAt`, `createdByAgent`, `createdBySession`. They form an append-only audit history; aggregate trend queries (score-over-time) walk this set.

## What this plugin does not do

- No LLM API calls. No citation monitor — out of scope. Multi-engine answer harvesting doesn't fit maxy-code's no-API-key architecture, and the monitor was archived without sprinting (Task 363). The audit plus the structured-answer template are the surface; check citation manually when needed.
- No automatic emission. `aeo-emit-jsonld` returns a script block; wiring it into the platform's page render path is per-renderer work, also filed as a follow-up.
- No prose authoring. AEO audits structure; it does not rewrite content. Writer-craft owns voice.

## See also

- User guide: `platform/plugins/docs/references/aeo.md`
- Structured-answer template: `platform/plugins/aeo/skills/structured-answer/SKILL.md`
- Schema declaration: `platform/neo4j/schema.cypher` (search `AEOAudit`)
- Schema reference: `platform/plugins/memory/schema-base.md` (search `AEOAudit`)
