Evaluated citeworthyio/seo-agent for reusable process knowledge. Relevant to this fleet's WordPress content sites (granja travel news, content-agent pipeline): a crawl-diagnose-approve-recrawl-measure loop for SEO metadata changes, a three-layer AI-crawler accessibility audit (robots policy, bot delivery, readable content), and a fail-closed method for generating and safely injecting Article JSON-LD. Keyword research and citation-probe pieces of the source repo were skipped as underdeveloped or too infra-coupled to be reusable here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
3.0 KiB
name, description, license, source
| name | description | license | source |
|---|---|---|---|
| grounded-article-jsonld | Use when generating, reviewing, storing, or injecting Article JSON-LD from page content. Prevent fabricated machine-readable claims and script-context injection while preserving existing structured data. | MIT | adapted from https://github.com/citeworthyio/seo-agent/blob/b78bb487f2819c3c7cc2ba6f3f5626ea0b841840/README.md#structured-data-json-ld and src/overrides.ts |
Grounded Article JSON-LD
Structured data is a factual publication, not decorative copy. An invented author or date becomes a machine-readable claim under the site's name and may be consumed without a reader ever seeing and correcting it.
Generate only from observed page facts
Give the generator only the page content actually fetched: title, description, canonical, visible article content, and explicit author/date/image fields. Tell it to omit anything it cannot point to in that material. Never infer an author, publisher, organization, date, image, rating, price, or other plausible default.
For an article page missing structured data, a minimal correct Article object
with @context, @type, and a grounded headline is better than a rich-looking
object containing guesses. Keep automated generation narrow to page-level types
such as Article; organization, product, rating, and similar business claims
need their own authoritative data source and review process.
Validate at every boundary
Use the same fail-closed validator for generated drafts, manual proposals, and the final publishing write:
- Parse as JSON.
- Accept one object or a non-empty array of objects, never primitives or null.
- Require every node to have an
@contextreferencingschema.organd a non-empty@type. - Enforce a bounded canonical serialization (the source implementation uses 8,192 characters).
- Reject the value rather than storing it if any check fails.
Using one validator matters: otherwise a draft can pass review and fail at publish time, or a manual path can bypass the protections applied to AI output.
Canonicalize for safe script embedding
Store JSON text without a <script> wrapper. After parsing, serialize it again
and replace literal < and > in the serialized bytes with JSON escapes
\u003c and \u003e. A JSON parser reconstructs the original characters, but
the stored bytes cannot close an enclosing script element or open an HTML
comment—even when the input expressed < through a JSON escape.
Do not use HTML entities such as < inside JSON: they change the data rather
than safely encoding JSON for a script context. At injection time, reject any
stored value that unexpectedly contains a literal <; it did not pass the
canonical write path.
Add the validated block alongside existing JSON-LD instead of replacing it. Multiple blocks are valid, while overwriting an origin block can silently erase publisher-authored facts. Verify the public response contains a parseable block of the intended type; presence proves less than byte-for-byte comparison, so do not overstate what that check establishes.