WP Manifestindependent plugin directory
manifest / ai / agent-ready-content

Agent Ready Content

A standalone WordPress VIP plugin that makes WordPress content discoverable and readable by AI agents.

by WPVIP · github.com/automattic/agent-ready-content

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/automattic/agent-ready-content/archive/refs/heads/trunk.zip

[!WARNING]

This plugin is currently in Beta, and breaking changes could occur with any update. DO NOT USE IT ON PRODUCTION ENVIRONMENTS.

Agent Ready Content

A WordPress VIP plugin that publishes posts and pages as Markdown and provides /llms.txt discovery. Requires WordPress 6.8+, PHP 8.2+, and the VIP platform runtime.

Derived from PRC Markdown for Agents by Pew Research Center. See NOTICE.md for attribution and source revisions, and LICENSE for the original GPL license.

Table of contents

Requirements

  • WordPress 6.8 or newer
  • PHP 8.2 or newer
  • The WordPress VIP platform runtime

Installation

Clone the repository into the WordPress plugins directory and build it:

git clone git@github.com:Automattic/agent-ready-content.git
cd agent-ready-content
nvm use
npm ci
npm run build

Activate Agent Ready Content from the WordPress Plugins screen.

On WordPress VIP, follow the documentation for activating plugins through code.

Use Settings → Agent Ready Content to edit the site summary, About links, categories, ordered featured posts, and additional resources. The site name and tagline provide neutral defaults.

Content and discovery

For a published post at /example/, the following return the same Markdown:

  • /example.md
  • /example/markdown (also accepts a trailing slash)
  • /example/?markdown=true

Sites using plain permalinks advertise the query-string form instead. Private content requires permission to read it. Password-protected content requires the password or edit permission and is excluded from the public featured index. Authenticated, preview, and password-authorized documents are not stored in the shared Markdown cache.

Output includes YAML metadata, the title, and converted content. HTML pages advertise alternate Markdown links and /llms.txt. The plugin preserves modern, nested, and legacy quotes, citations, lists, tables, links, images, and code. Unrecognized leaf blocks use HTML conversion; container blocks process children.

Accept: text/markdown negotiation is disabled by default. Enable AGENT_READY_CONTENT_ENABLE_ACCEPT_NEGOTIATION only after verifying that the site's cache separates negotiated Markdown from HTML. Discovery and dedicated URLs do not require it. The existing Content-Signal defaults are retained and can be configured with the agent_ready_content_content_signal option.

The plugin uses VIP URL lookup and edge-purge APIs when available, with core fallbacks for local development. /llms.txt is handled during parse_request, without stored rewrite rules or a helper file. WordPress’s robots_txt filter adds discovery where the platform permits it; VIP test-domain crawler restrictions still apply. Actual edge-cache refresh requires deployment verification.

Build the settings assets

composer install
nvm use
npm ci
npm run format:check
npm run typecheck
npm run lint:js
npm run build
composer phpcs
composer test:unit

Composer installs development-only PHP tooling. The plugin does not load vendor/ at runtime, and that directory is not included in deployments.

The repository's integrations/ directory is also excluded from the base plugin release package. Integrations must be installed and loaded as separate WordPress plugins.

The settings source uses strict TypeScript and core WordPress components. index.tsx mounts the page; app.tsx arranges its sections. The hooks/ directory contains loading, queued saving, section drafts, and post search. Shared controls live in components/, and the settings forms live in sections/. The build uses @wordpress/scripts locally and generates a dependency manifest. All npm packages are development dependencies; .nvmrc selects Node 24. WordPress provides the runtime packages.

Run the complete check set before proposing a change:

npm run typecheck
npm run lint:js
npm run format:check
npm run build
composer phpcs
composer test:unit
npx wp-env start
npm run test:integration

Extend the base

All PHP classes live in Agent_Ready_Content. Hook names, options, cache groups, and the REST namespace use agent_ready_content / agent-ready-content.

Register a block callback before init priority 5. Integrations should register block types on init, after the plugin has installed its metadata filter:

add_action( 'agent_ready_content_register_block_callbacks', static function () {
    \Agent_Ready_Content\Block_Markdown_Registry::register(
        'example/quote',
        static function ( array $block, \WP_Post $post ): string {
            return '> ' . sanitize_text_field( $block['attrs']['text'] ?? '' );
        }
    );
} );

Callbacks receive the parsed block and its post and return Markdown. An empty string suppresses the block. Registry methods register(), get(), and has() are public. A later registration for the same block name replaces the earlier one.

A block can alternatively declare metadata in block.json:

{
    "agentReadyContent": {
        "callback": "Example\\Markdown::convert"
    }
}

The callable must be loaded before conversion. Metadata modes strip and children-only take precedence over metadata callbacks; metadata handling takes precedence over registry callbacks. Registry output then passes through agent_ready_content_block_{block-name}. That filter does not run for the metadata path. Preserve this distinction when adding integrations.

Extension point Contract
agent_ready_content_pre_markdown Return null to continue, or a string to supply the document body before block conversion. Receives the post.
agent_ready_content_after_markdown Filter the body when serving a document. Direct post_to_markdown() calls do not run this filter.
agent_ready_content_authors Return author entries containing name and optional job_title and link; receives the post.
agent_ready_content_frontmatter Filter the metadata array; receives the post.
agent_ready_content_llms_txt_sections Append section arrays with slug, title, links, and optional description. Duplicate slugs keep the first section.
agent_ready_content_additional_resources_blocks Filter resource blocks containing id, title, and body.
agent_ready_content_settings_defaults Supply defaults for unsaved settings without overwriting saved values.
agent_ready_content_set_context / agent_ready_content_clear_context Set or clear a conversion context. Read it with Block_Markdown_Registry::get_context(). Use try/finally to clear it after failures.

Enable another post type with add_post_type_support( $type, 'agent-ready-content' ). Declare agent-ready-content-llms-txt support when its updates contribute to the index. Provider-specific data, queries, and dependencies remain outside the base plugin.

Integration example

The separately loaded PRC Bridge shows how current PRC Markdown for Agents integrations can work with Agent Ready Content without shipping PRC compatibility code in the base plugin.

When related data changes, integrations identify the affected article IDs and call:

\Agent_Ready_Content\Markdown_Cache_Invalidator::invalidate_post( $article_id );
\Agent_Ready_Content\Llms_Txt_Cache_Invalidator::purge_cache();

The first call clears the article and its parent, including supported page-cache purges. Moving a child also clears its former parent. Category/tag edits and author display-name changes clear affected documents, with the first 100 handled immediately and further batches scheduled through WordPress for VIP Cron Control. The 100-document limit bounds each callback’s work. VIP queues and deduplicates URL purge requests; this does not synchronously purge the edge cache. The second clears /llms.txt. Call before permanent deletion if a purge needs the old permalink. A callback that only generates different output does not itself invalidate a previously cached response.

Metadata and settings contracts

Frontmatter accepts nested PHP arrays (maps or lists), strings, finite numbers, booleans, and null, with a maximum nesting depth of 32. Empty arrays render as empty lists. Objects and resources are unsupported. Mapping keys and strings are quoted; Unicode and escaped line breaks survive a YAML round trip.

Settings defaults are calculated when read. Saving a section stores that section's overrides without copying defaults or filtered resources from other sections into the option. The additional-resources filter still represents integration-maintained output; use the defaults filter for editable starter text.

Content-Signal accepts yes/no, true/false, booleans, and 1/0 for ai-train, search, and ai-input. Unknown keys and values are omitted. The original all-yes defaults remain in place. Legacy PRC settings migration and legacy filter translation belong in the separate PRC Bridge, not this base.

Contributing

See CONTRIBUTING.md for local setup, the plugin architecture, test coverage, common change recipes, and the release boundaries between the base plugin and integrations.