Skip to main content

ByUpdated

Implementation

Implementation Plan

A phased, week-by-week rollout guide for implementing all five Defense in Depth layers of BiModal Design — from basic FR-1 compliance to full agent protocol support.

Overview

BiModal Design is implemented in six sequential phases. Each phase builds on the previous and unlocks a new category of agent access. You can stop at any phase — partial implementation still delivers measurable value.

1
FR-1 ComplianceWeek 1–2

All content in initial HTTP response. Enables curl/HTTP agents.

2
Semantic StructureWeek 2–3

HTML5 landmarks, ARIA, heading hierarchy. Enables structured parsing.

3
Structured DataWeek 3–4

Schema.org microdata and JSON-LD. Enables knowledge graph agents.

4
API SurfaceWeek 4–5

OpenAPI spec, API discovery link. Enables API-capable agents.

5
Agent ProtocolsWeek 5–6

MCP server, Agent Card. Enables MCP/A2A protocol agents.

6
Testing & ValidationOngoing

Per-layer automated tests, monitoring, and regression prevention.

1

Phase 1: FR-1 Compliance

Week 1–2

Foundational Requirement 1: every piece of content agents need must be present in the raw HTML returned by the initial HTTP response. No client-side rendering for primary content.

Verification test:

# Test FR-1 compliance: all content must be in initial HTTP response
curl -s https://yoursite.com/products \
  | grep -c "data-agent-component"

# Must return > 0 — if it returns 0, content is client-rendered (FR-1 FAIL)

# Verify specific content is present
curl -s https://yoursite.com/products \
  | grep -o 'data-agent-page="[^"]*"'
# Expected: data-agent-page="product-listing"

Next.js implementation

// app/products/page.tsx — Server Component (default in Next.js 13+)
// Content rendered on server = FR-1 compliant

async function getProducts() {
  const res = await fetch('https://api.yoursite.com/products', {
    next: { revalidate: 3600 }, // ISR: revalidate every hour
  });
  return res.json();
}

export default async function ProductsPage() {
  const products = await getProducts();

  return (
    <main
      data-agent-page="product-listing"
      data-agent-intent="browse"
      data-agent-content-type="listing"
    >
      <h1 data-agent-content="page-title">Our Products</h1>
      <ul data-agent-component="product-list">
        {products.map((product) => (
          <li
            key={product.id}
            data-agent-component="product-card"
            data-agent-content-type="product"
          >
            <h2 data-agent-content="product-name">{product.name}</h2>
            <p data-agent-content="product-price">${product.price}</p>
            <a
              href={`/products/${product.id}`}
              data-agent-action="view-product-details"
            >
              View Details
            </a>
          </li>
        ))}
      </ul>
    </main>
  );
}

Framework note

React/Next.js App Router Server Components are FR-1 compliant by default. Pure client components ('use client' with useEffect data fetching) are not. Move data fetching to the server.

2

Phase 2: Semantic Structure

Week 2–3

Add HTML5 landmarks, ARIA roles, a logical heading hierarchy, and data-agent-* attributes so agents can navigate and understand page structure without executing JavaScript.

<!-- Layer 2: Semantic HTML with ARIA landmarks -->
<!DOCTYPE html>
<html lang="en" data-agent-framework="nextjs" data-agent-mode="ssg">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Product Catalog — YourSite</title>
  <meta name="description" content="Browse our full product catalog">
</head>
<body>
  <!-- Skip link for keyboard/agent navigation -->
  <a
    href="#main-content"
    class="sr-only focus:not-sr-only"
    data-agent-action="skip-to-content"
  >
    Skip to main content
  </a>

  <header role="banner">
    <nav
      aria-label="Main navigation"
      data-agent-component="navigation"
    >
      <a href="/" data-agent-action="go-home">Home</a>
      <a href="/products" data-agent-action="view-products">Products</a>
      <a href="/support" data-agent-action="get-support">Support</a>
    </nav>
  </header>

  <main id="main-content" role="main"
    data-agent-page="product-listing"
    data-agent-intent="browse"
  >
    <!-- Content here -->
  </main>

  <footer role="contentinfo">
    <!-- Footer content -->
  </footer>
</body>
</html>

Required HTML5 landmarks

  • <header role="banner"> — site header
  • <nav aria-label="..."> — navigation regions
  • <main role="main"> — primary content (one per page)
  • <footer role="contentinfo"> — site footer
  • <aside role="complementary"> — supplementary content

Heading hierarchy rules

  • One h1 per page — the page title
  • Don't skip levels (h1 → h3 is invalid)
  • Use data-agent-content="page-title" on the h1
  • Use data-agent-content="section-title" on h2/h3
3

Phase 3: Structured Data

Week 3–4

Add Schema.org structured data using both inline microdata (for zero-JS fallback) and JSON-LD (for rich extraction). Both formats in the initial HTTP response.

<!-- Layer 3: Structured Data — inline microdata + JSON-LD -->

<!-- Microdata (inline, works without JS) -->
<article
  itemscope
  itemtype="https://schema.org/Product"
  data-agent-component="product-card"
>
  <h2 itemprop="name" data-agent-content="product-name">
    Wireless Headphones Pro
  </h2>
  <p itemprop="description" data-agent-content="product-description">
    Premium noise-cancelling audio
  </p>
  <div itemprop="offers" itemscope itemtype="https://schema.org/Offer">
    <span itemprop="price" data-agent-content="product-price">$299</span>
    <meta itemprop="priceCurrency" content="USD">
    <link itemprop="availability" href="https://schema.org/InStock">
  </div>
</article>

<!-- JSON-LD (in <head> or at bottom of <body>) -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Headphones Pro",
  "description": "Premium noise-cancelling audio",
  "offers": {
    "@type": "Offer",
    "price": "299",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  }
}
</script>

Schema types by page type

Product — product detail pages
Article — blog posts, docs
WebSite — homepage
Organization — about, company
BreadcrumbList — navigation path
FAQPage — FAQ sections
4

Phase 4: API Surface

Week 4–5

Expose a machine-readable API with an OpenAPI specification and make it discoverable via <link rel="api"> in your page head.

OpenAPI specification

# Layer 4: OpenAPI specification
# Place at /api/openapi.json or /api/openapi.yaml

openapi: "3.0.3"
info:
  title: YourSite API
  version: "1.0.0"
  description: |
    RESTful API for YourSite product catalog and ordering.
    Designed for both human-facing integrations and AI agent access.
  contact:
    name: API Support
    url: https://yoursite.com/support

servers:
  - url: https://yoursite.com/api/v1
    description: Production

paths:
  /products:
    get:
      operationId: listProducts
      summary: List all products
      description: Returns paginated product catalog with full agent-readable data
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        "200":
          description: Product list
          content:
            application/json:
              schema:
                type: object
                properties:
                  products:
                    type: array
                    items:
                      $ref: "#/components/schemas/Product"

components:
  schemas:
    Product:
      type: object
      required: [id, name, price]
      properties:
        id:
          type: string
        name:
          type: string
        price:
          type: number
        currency:
          type: string
          default: USD

API discovery links

<!-- Add to <head> for API discoverability by agents -->
<link rel="api" href="/api/openapi.json" type="application/json">
<link rel="api" href="/api/openapi.yaml" type="application/yaml">

<!-- Layer 5: MCP Server Discovery -->
<link rel="alternate" type="application/mcp+json" href="/mcp-server" />

<!-- Also add sitemap and robots.txt references -->
<link rel="sitemap" href="/sitemap.xml" type="application/xml">
5

Phase 5: Agent Protocols

Week 5–6

Implement the Model Context Protocol (MCP) for agentic tool use, and publish an Agent Card at /.well-known/agent.json for A2A protocol discovery.

MCP server

// Layer 5: MCP Server (Model Context Protocol)
// Install: npm install @modelcontextprotocol/sdk

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';

const server = new Server(
  { name: 'yoursite-mcp', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: 'search_products',
      description: 'Search the product catalog',
      inputSchema: {
        type: 'object',
        properties: {
          query: { type: 'string', description: 'Search query' },
          maxResults: { type: 'number', default: 10 },
        },
        required: ['query'],
      },
    },
    {
      name: 'get_product',
      description: 'Get full details for a specific product',
      inputSchema: {
        type: 'object',
        properties: {
          productId: { type: 'string' },
        },
        required: ['productId'],
      },
    },
  ],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name === 'search_products') {
    const results = await fetch(
      `https://yoursite.com/api/v1/products?q=${encodeURIComponent(args.query)}`
    ).then((r) => r.json());

    return {
      content: [
        {
          type: 'text',
          text: JSON.stringify(results.products.slice(0, args.maxResults ?? 10)),
        },
      ],
    };
  }

  throw new Error(`Unknown tool: ${name}`);
});

const transport = new StdioServerTransport();
await server.connect(transport);

Agent Card

// Place at /.well-known/agent.json
// This is the Agent Card — discoverable by A2A protocol clients

{
  "schemaVersion": "1.0",
  "name": "YourSite Agent",
  "description": "AI agent interface for YourSite product catalog and ordering",
  "version": "1.0.0",
  "url": "https://yoursite.com",
  "capabilities": {
    "streaming": false,
    "pushNotifications": false,
    "stateTransitionHistory": false
  },
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json"],
  "skills": [
    {
      "id": "product-search",
      "name": "Product Search",
      "description": "Search and browse the product catalog",
      "tags": ["products", "catalog", "search"],
      "examples": [
        "Find wireless headphones under $200",
        "Show me all laptops in stock"
      ]
    },
    {
      "id": "order-assistance",
      "name": "Order Assistance",
      "description": "Help with placing and tracking orders",
      "tags": ["orders", "checkout", "tracking"]
    }
  ]
}
6

Phase 6: Testing & Validation

Ongoing

Run per-layer validation tests after each phase. Automate these in CI to prevent regressions when content or code changes.

# Phase 6: Validate all 5 layers

echo "=== Layer 1: FR-1 Check ==="
CONTENT_COUNT=$(curl -s https://yoursite.com/products | grep -c "data-agent-component")
echo "Agent components found: $CONTENT_COUNT"
[ $CONTENT_COUNT -gt 0 ] && echo "PASS" || echo "FAIL: Content not in initial response"

echo ""
echo "=== Layer 2: Semantic Structure ==="
LANDMARKS=$(curl -s https://yoursite.com | grep -E '<(main|nav|header|footer|aside)' | wc -l)
echo "HTML5 landmarks found: $LANDMARKS"
[ $LANDMARKS -ge 3 ] && echo "PASS" || echo "WARN: Add more HTML5 landmarks"

echo ""
echo "=== Layer 3: Structured Data ==="
curl -s https://yoursite.com/products/sample | python3 -c "
import sys, json, re
html = sys.stdin.read()
ld = re.findall(r'<script type=.application/ld+json.>(.*?)</script>', html, re.DOTALL)
print(f'JSON-LD blocks found: {len(ld)}')
for block in ld:
    try:
        data = json.loads(block)
        print(f'  @type: {data.get(chr(64)+"type", "unknown")}')
    except:
        print('  [parse error]')
"

echo ""
echo "=== Layer 4: API Discovery ==="
curl -si https://yoursite.com | grep -i 'link.*api'
curl -s https://yoursite.com/api/openapi.json | python3 -c "
import sys, json
data = json.load(sys.stdin)
paths = len(data.get('paths', {}))
print(f'OpenAPI paths: {paths}')
[ paths > 0 ] and print('PASS') or print('FAIL')
" 2>/dev/null || echo "No OpenAPI spec found"

echo ""
echo "=== Layer 5: Agent Protocols ==="
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://yoursite.com/.well-known/agent.json)
echo "Agent Card status: $HTTP_CODE"
[ "$HTTP_CODE" = "200" ] && echo "PASS" || echo "FAIL: Agent Card not found"

Implementation Checklist

Layer 1: FR-1 Compliance

  • All primary content rendered server-side (SSR/SSG)
  • curl test returns > 0 data-agent-component matches
  • No critical data loaded in useEffect or client-side fetch
  • Progressive enhancement: core functionality works without JS
  • noscript fallback for any JS-dependent components

Layer 2: Semantic Structure

  • HTML5 landmarks: header, nav, main, footer present
  • One h1 per page with data-agent-content="page-title"
  • No skipped heading levels
  • nav elements have aria-label attributes
  • Skip-to-content link with data-agent-action="skip-to-content"
  • data-agent-framework and data-agent-mode on <html>
  • data-agent-page and data-agent-intent on <main>
  • data-agent-component on major UI sections
  • data-agent-action on interactive elements

Layer 3: Structured Data

  • JSON-LD in <head> for primary page entity
  • Schema.org type matches page content type
  • Microdata on key content elements (optional but recommended)
  • BreadcrumbList on multi-level navigation pages
  • Google Rich Results Test passes with no errors

Layer 4: API Surface

  • OpenAPI 3.x spec at /api/openapi.json
  • <link rel="api"> in page <head>
  • All endpoints documented with descriptions
  • Authentication documented in securitySchemes
  • robots.txt references API spec location

Layer 5: Agent Protocols

  • MCP server implemented and deployed
  • Agent Card at /.well-known/agent.json returns 200
  • Agent Card skills reflect actual capabilities
  • robots.txt allows agent crawlers
  • llms.txt at /llms.txt (optional, for LLM context)