Expand description
Agent JSON API emitter (issue #586, port 3 of 5).
Port of the site’s Python-pipeline AgentApiPlugin (~382 LOC): a
stable, machine-readable JSON API for AI crawlers and agent
toolchains. Complements crate::ai::AiPlugin (llms.txt /
llms-full.txt) and the agentic-discovery emitters
(agents.txt + ai-plugin.json + mcp.json, issue #552) with a
queryable content surface rather than a prose one.
§Files emitted (under <site>/api/agents/)
| File | Shape |
|---|---|
index.json | API descriptor: site identity, entry counts, absolute links to the other three documents |
posts.json | Array of {title, url, date, description, tags, locale, wordCount} — one entry per public content page |
topics.json | Object mapping each tag / topic-cluster term to the sorted member post URLs |
person.json | JSON-LD (schema.org) Person entity for the site author |
§Data sources
Frontmatter is read from the .meta.json sidecars the compiler
emits under <build>/.meta/ (the same convention consumed by
crate::taxonomy::TaxonomyPlugin and the MCP auto_resources
walker). When the build-dir sidecars are absent (ad-hoc pipelines),
*.meta.json files next to the HTML in site_dir are used as a
fallback.
wordCount resolution order (per the tracker):
- the sidecar’s
word_countfield (stamped byfrontmatter::emit_sidecars), - a
wordCountfield lifted from a renderedBlogPosting/ArticleJSON-LD block in the page HTML, - a manual word count over
ssg_core::strip_html_tagsoutput.
§Default-on and lifecycle
Registered unconditionally by
pipeline::register_default_plugins — the same default-on, no
ssg.toml knob convention crate::ai::AiPlugin follows (the
repo’s other opt-in plugins gate by not being registered, e.g.
crate::search_index::VectorSearchPlugin). Programmatic opt-out
is available via AgentApiPlugin::disabled. Runs in
after_compile and honours ctx.dry_run.
§Determinism
Output must be byte-identical across rebuilds (determinism.yml
hashes the site): posts are sorted by URL, tag lists are sorted +
deduplicated, topics use a BTreeMap, and serde_json’s default
BTreeMap-backed object keeps key order canonical. No timestamps
are embedded.
Structs§
- Agent
ApiPlugin - Plugin that emits
/api/agents/{index,posts,topics,person}.json. - Post
Entry - One public content page, normalised from its
.meta.jsonsidecar.
Functions§
- collect_
posts - Collects public posts from
.meta.jsonsidecars. - jsonld_
word_ count - Lifts
wordCountfrom any<script type="application/ld+json">block in the page (BlogPosting/Articleemit it in the Python original this port mirrors). - parse_
author - Parses
email (Name)andName <email>author conventions.