diff --git a/package.json b/package.json index 1ba603f0..10648de1 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "preview": "astro preview", "optimize:article-images": "node scripts/optimize-article-images.mjs", "optimize:blog-banners": "node scripts/optimize-blog-banners.mjs", + "audit:indexability": "node scripts/audit-live-indexability.mjs", "check:plain": "node scripts/check-plain-coverage.mjs", "check:site": "node scripts/check-site-integrity.mjs" }, diff --git a/scripts/audit-live-indexability.mjs b/scripts/audit-live-indexability.mjs new file mode 100644 index 00000000..ffd70082 --- /dev/null +++ b/scripts/audit-live-indexability.mjs @@ -0,0 +1,321 @@ +#!/usr/bin/env node + +import { writeFile } from 'node:fs/promises'; + +const origin = (process.env.SITE_URL || 'https://pilotprotocol.network').replace(/\/$/, ''); +const reportPath = process.env.AUDIT_REPORT || ''; +const concurrency = Math.max(1, Number(process.env.AUDIT_CONCURRENCY || 10)); +const googlebot = 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'; + +const escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + +const robotsGroups = (body = '') => { + const groups = []; + let agents = []; + let rules = []; + const flush = () => { + if (agents.length) groups.push({ agents, rules }); + agents = []; + rules = []; + }; + + for (const rawLine of body.split(/\r?\n/)) { + const line = rawLine.replace(/#.*$/, '').trim(); + if (!line) { + if (rules.length) flush(); + continue; + } + const match = line.match(/^([^:]+):\s*(.*)$/); + if (!match) continue; + const field = match[1].trim().toLowerCase(); + const value = match[2].trim(); + if (field === 'user-agent') { + if (rules.length) flush(); + agents.push(value.toLowerCase()); + } else if ((field === 'allow' || field === 'disallow') && agents.length) { + rules.push({ field, value }); + } + } + flush(); + return groups; +}; + +const robotsAllows = (groups, url, agent = 'googlebot') => { + const matching = groups + .map((group) => ({ + ...group, + specificity: Math.max(-1, ...group.agents.map((token) => token === '*' ? 0 : agent.includes(token) ? token.length : -1)), + })) + .filter((group) => group.specificity >= 0); + if (!matching.length) return true; + const specificity = Math.max(...matching.map((group) => group.specificity)); + const rules = matching.filter((group) => group.specificity === specificity).flatMap((group) => group.rules); + const path = `${new URL(url).pathname}${new URL(url).search}`; + const matched = rules + .filter((rule) => rule.value) + .map((rule) => { + const anchored = rule.value.endsWith('$'); + const pattern = anchored ? rule.value.slice(0, -1) : rule.value; + const expression = `^${escapeRegExp(pattern).replaceAll('\\*', '.*')}${anchored ? '$' : ''}`; + return new RegExp(expression).test(path) ? { ...rule, length: pattern.replaceAll('*', '').length } : null; + }) + .filter(Boolean) + .sort((a, b) => b.length - a.length || Number(b.field === 'allow') - Number(a.field === 'allow')); + return matched[0]?.field !== 'disallow'; +}; + +const decode = (value = '') => value + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'|'/g, "'") + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/&#(\d+);/g, (_, code) => String.fromCodePoint(Number(code))) + .replace(/&#x([\da-f]+);/gi, (_, code) => String.fromCodePoint(Number.parseInt(code, 16))); + +const text = (html = '') => decode(html) + .replace(/]*>[\s\S]*?<\/script>/gi, ' ') + .replace(/]*>[\s\S]*?<\/style>/gi, ' ') + .replace(/]*>[\s\S]*?<\/svg>/gi, ' ') + .replace(/<[^>]+>/g, ' ') + .replace(/\s+/g, ' ') + .trim(); + +const attr = (tag, name) => { + const match = tag.match(new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)'|([^\\s>]+))`, 'i')); + return decode(match?.[1] ?? match?.[2] ?? match?.[3] ?? ''); +}; + +const canonicalUrl = (value) => { + try { + const url = new URL(value, origin); + url.hash = ''; + url.search = ''; + return url.toString(); + } catch { + return ''; + } +}; + +const pageGroup = (url) => { + const path = new URL(url).pathname; + const root = path.split('/').filter(Boolean)[0] || 'home'; + return root; +}; + +const shingles = (value, size = 5) => { + const words = value.toLowerCase().replace(/[^\p{L}\p{N}]+/gu, ' ').trim().split(/\s+/).filter(Boolean); + const result = new Set(); + for (let i = 0; i <= words.length - size; i += 1) result.add(words.slice(i, i + size).join(' ')); + return result; +}; + +const similarity = (left, right) => { + if (!left.size || !right.size) return 0; + const smaller = left.size < right.size ? left : right; + const larger = smaller === left ? right : left; + let intersection = 0; + for (const item of smaller) if (larger.has(item)) intersection += 1; + return intersection / (left.size + right.size - intersection); +}; + +async function fetchText(url, redirect = 'follow') { + const response = await fetch(url, { + redirect, + headers: { 'user-agent': googlebot, accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' }, + signal: AbortSignal.timeout(20_000), + }); + return { response, body: await response.text() }; +} + +const sitemapUrl = `${origin}/sitemap.xml`; +const { response: sitemapResponse, body: sitemap } = await fetchText(sitemapUrl); +if (!sitemapResponse.ok) throw new Error(`Sitemap returned HTTP ${sitemapResponse.status}: ${sitemapUrl}`); + +const robotsUrl = `${origin}/robots.txt`; +let robotsStatus = 0; +let parsedRobots = []; +let robotsError = ''; +try { + const { response, body } = await fetchText(robotsUrl); + robotsStatus = response.status; + if (response.ok) parsedRobots = robotsGroups(body); + else if (response.status >= 500 || response.status === 429) robotsError = `HTTP ${response.status}`; +} catch (error) { + robotsError = error instanceof Error ? error.message : String(error); +} + +const sitemapEntries = [...sitemap.matchAll(/\s*([^<]+)<\/loc>(?:\s*([^<]+)<\/lastmod>)?[\s\S]*?<\/url>/gi)] + .map(([, loc, lastmod]) => ({ url: decode(loc), lastmod: lastmod || '' })); + +const results = new Array(sitemapEntries.length); +let cursor = 0; +async function worker() { + while (cursor < sitemapEntries.length) { + const index = cursor; + cursor += 1; + const entry = sitemapEntries[index]; + try { + const { response, body } = await fetchText(entry.url, 'manual'); + const contentType = response.headers.get('content-type') || ''; + const metaTags = body.match(/]*>/gi) || []; + const linkTags = body.match(/]*>/gi) || []; + const robotsTag = metaTags.find((tag) => attr(tag, 'name').toLowerCase() === 'robots'); + const googlebotTag = metaTags.find((tag) => attr(tag, 'name').toLowerCase() === 'googlebot'); + const descriptionTag = metaTags.find((tag) => attr(tag, 'name').toLowerCase() === 'description'); + const canonicalTags = linkTags.filter((tag) => attr(tag, 'rel').toLowerCase().split(/\s+/).includes('canonical')); + const canonicalTag = canonicalTags[0]; + const mainMatch = body.match(/]*>([\s\S]*?)<\/main>/i); + const mainText = text(mainMatch?.[1] || body.match(/]*>([\s\S]*?)<\/body>/i)?.[1] || body); + const title = text(body.match(/]*>([\s\S]*?)<\/title>/i)?.[1] || ''); + const links = []; + for (const tag of body.match(/]*>/gi) || []) { + const href = attr(tag, 'href'); + if (!href || /^(?:mailto:|tel:|javascript:)/i.test(href)) continue; + try { + const target = new URL(href, entry.url); + if (target.origin !== new URL(origin).origin) continue; + target.hash = ''; + target.search = ''; + links.push(target.toString()); + } catch { /* malformed href is reported by the build-time integrity check */ } + } + + let invalidJsonLd = 0; + let jsonLdCount = 0; + for (const match of body.matchAll(/]*type\s*=\s*["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi)) { + jsonLdCount += 1; + try { JSON.parse(match[1]); } catch { invalidJsonLd += 1; } + } + + results[index] = { + ...entry, + status: response.status, + location: response.headers.get('location') || '', + contentType, + xRobots: response.headers.get('x-robots-tag') || '', + title, + description: attr(descriptionTag || '', 'content'), + robots: attr(robotsTag || '', 'content'), + googlebot: attr(googlebotTag || '', 'content'), + robotsAllowed: robotsAllows(parsedRobots, entry.url), + canonicalCount: canonicalTags.length, + canonical: canonicalUrl(attr(canonicalTag || '', 'href')), + expectedCanonical: canonicalUrl(entry.url), + h1Count: (body.match(/ worker())); + +const sitemapSet = new Set(sitemapEntries.map((entry) => canonicalUrl(entry.url))); +const inbound = new Map([...sitemapSet].map((url) => [url, 0])); +for (const page of results) { + for (const link of page.links || []) { + const normalized = canonicalUrl(link); + if (normalized !== page.expectedCanonical && inbound.has(normalized)) inbound.set(normalized, inbound.get(normalized) + 1); + } +} + +const blockers = []; +const warnings = []; +const add = (list, type, page, detail) => list.push({ type, url: page.url, detail }); +const today = new Date().toISOString().slice(0, 10); + +if (robotsError) blockers.push({ type: 'robots-unavailable', url: robotsUrl, detail: robotsError }); + +for (const page of results) { + if (page.error) { add(blockers, 'fetch-error', page, page.error); continue; } + if (page.status !== 200) add(blockers, 'sitemap-non-200', page, `HTTP ${page.status}${page.location ? ` → ${page.location}` : ''}`); + if (!page.contentType.includes('text/html')) add(blockers, 'non-html', page, page.contentType || 'missing content-type'); + if (!page.robotsAllowed) add(blockers, 'robots-blocked', page, 'Disallowed for Googlebot'); + if (/noindex/i.test(`${page.robots} ${page.googlebot} ${page.xRobots}`)) add(blockers, 'noindex-in-sitemap', page, `${page.robots} ${page.googlebot} ${page.xRobots}`.trim()); + if (page.canonicalCount > 1) add(blockers, 'multiple-canonicals', page, `${page.canonicalCount} canonical links`); + if (!page.canonical) add(blockers, 'missing-canonical', page, 'No canonical link'); + else if (page.canonical !== page.expectedCanonical) add(blockers, 'canonical-mismatch', page, `${page.canonical} != ${page.expectedCanonical}`); + if (!page.title) add(blockers, 'missing-title', page, 'No title'); + if (!page.description) add(blockers, 'missing-description', page, 'No meta description'); + if (page.h1Count !== 1) add(blockers, 'h1-count', page, `${page.h1Count} H1 elements`); + if (page.invalidJsonLd) add(blockers, 'invalid-json-ld', page, `${page.invalidJsonLd}/${page.jsonLdCount} invalid blocks`); + if (page.lastmod && page.lastmod > today) add(blockers, 'future-lastmod', page, page.lastmod); + if (page.expectedCanonical !== `${origin}/` && (inbound.get(page.expectedCanonical) || 0) === 0) add(blockers, 'orphan', page, 'No crawlable internal link from another sitemap URL'); + + if (page.title && (page.title.length < 30 || page.title.length > 60)) add(warnings, 'title-length', page, `${page.title.length} characters`); + if (page.description && (page.description.length < 120 || page.description.length > 160)) add(warnings, 'description-length', page, `${page.description.length} characters`); + if (page.wordCount < 150) add(warnings, 'thin-main-content', page, `${page.wordCount} words`); + if (!page.jsonLdCount) add(warnings, 'missing-json-ld', page, 'No structured-data block'); + if (/nofollow/i.test(`${page.robots} ${page.googlebot} ${page.xRobots}`)) add(warnings, 'nofollow-page', page, 'Page-level nofollow limits link discovery'); +} + +for (const field of ['title', 'description', 'canonical']) { + const buckets = new Map(); + for (const page of results) { + const value = page[field]; + if (!value) continue; + const key = field === 'canonical' ? value : value.toLowerCase(); + if (!buckets.has(key)) buckets.set(key, []); + buckets.get(key).push(page.url); + } + for (const urls of buckets.values()) { + if (urls.length < 2) continue; + for (const url of urls) warnings.push({ type: `duplicate-${field}`, url, detail: `${urls.length} pages share this ${field}` }); + } +} + +const similar = []; +const grouped = Map.groupBy(results.filter((page) => page.wordCount >= 150), (page) => pageGroup(page.url)); +for (const [group, pages] of grouped) { + for (let left = 0; left < pages.length; left += 1) { + for (let right = left + 1; right < pages.length; right += 1) { + const score = similarity(pages[left].shingleSet, pages[right].shingleSet); + if (score >= 0.55) similar.push({ group, score, left: pages[left].url, right: pages[right].url }); + } + } +} +similar.sort((a, b) => b.score - a.score); + +const counts = (issues) => Object.fromEntries( + [...Map.groupBy(issues, (issue) => issue.type)].map(([type, entries]) => [type, entries.length]).sort((a, b) => b[1] - a[1]), +); + +const serializableResults = results.map(({ mainText, shingleSet, links, ...page }) => ({ ...page, inboundLinks: inbound.get(page.expectedCanonical) || 0 })); +const report = { + generatedAt: new Date().toISOString(), + origin, + sitemapUrl, + robotsUrl, + robotsStatus, + pages: results.length, + blockers, + warnings, + nearDuplicates: similar, + blockerCounts: counts(blockers), + warningCounts: counts(warnings), + results: serializableResults, +}; + +console.log(`Live indexability audit: ${results.length} sitemap URLs`); +console.log(`Blockers: ${blockers.length}`, report.blockerCounts); +console.log(`Warnings: ${warnings.length}`, report.warningCounts); +console.log(`Near-duplicate pairs (>=55% five-word shingles): ${similar.length}`); + +for (const issue of blockers.slice(0, 40)) console.log(`BLOCKER ${issue.type}: ${issue.url} — ${issue.detail}`); +for (const issue of warnings.slice(0, 40)) console.log(`WARN ${issue.type}: ${issue.url} — ${issue.detail}`); +for (const pair of similar.slice(0, 30)) console.log(`SIMILAR ${(pair.score * 100).toFixed(1)}% [${pair.group}]: ${pair.left} <> ${pair.right}`); + +if (reportPath) { + await writeFile(reportPath, `${JSON.stringify(report, null, 2)}\n`); + console.log(`Report: ${reportPath}`); +} + +if (blockers.length) process.exitCode = 1; diff --git a/src/components/Footer.astro b/src/components/Footer.astro index a1623020..b9056e2e 100644 --- a/src/components/Footer.astro +++ b/src/components/Footer.astro @@ -338,7 +338,7 @@ const socials = [ justify-content: space-between; gap: 16px; margin-bottom: 18px; - color: color-mix(in srgb, var(--ink-dim) 58%, transparent); + color: var(--ink-dim); font-family: var(--mono); font-size: 9px; font-weight: 500; @@ -346,7 +346,7 @@ const socials = [ letter-spacing: .12em; text-transform: uppercase; } - .foot-solutions-intro span:last-child { opacity: .62; } + .foot-solutions-intro span:last-child { opacity: .85; } .foot-solutions-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); @@ -354,7 +354,7 @@ const socials = [ } .foot-solutions-group p { margin: 0 0 9px; - color: color-mix(in srgb, var(--ink-dim) 58%, transparent); + color: var(--ink-dim); font-family: var(--mono); font-size: 9px; line-height: 1.2; @@ -369,7 +369,7 @@ const socials = [ .foot-solutions-group a { display: inline-flex; align-items: center; - color: color-mix(in srgb, var(--ink-dim) 64%, transparent); + color: var(--ink-dim); font-size: 11px; line-height: 1.45; text-decoration: none; @@ -400,6 +400,17 @@ const socials = [ .site-footer { padding: 56px 0 32px; } .foot-solutions-intro span:last-child { display: none; } .foot-solutions-grid { grid-template-columns: 1fr; gap: 18px; } - .foot-solutions-group a { font-size: 10.5px; } + .foot-solutions-group > div { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0 14px; + } + .foot-solutions-group a { + min-height: 30px; + padding: 6px 0; + font-size: 10.5px; + line-height: 1.65; + } + .foot-solutions-group a:not(:last-child)::after { display: none; } } diff --git a/src/data/blogPosts.json b/src/data/blogPosts.json index 7359adc8..c8537942 100644 --- a/src/data/blogPosts.json +++ b/src/data/blogPosts.json @@ -48,7 +48,7 @@ "slug": "web-search-api-for-ai-agents-grounded-research", "title": "Web Search API for AI Agents: Grounded Research with cosift", "description": "Why raw search APIs aren't enough for AI agents, what grounded research means, and how to install and call cosift's search, answer, and research methods.", - "date": "Jul 2", + "date": "Jul 3", "category": "Blog", "tags": [ "app-store", @@ -57,7 +57,7 @@ "research" ], "banner": "banners/web-search-api-for-ai-agents-grounded-research.svg", - "iso_date": "2026-07-02" + "iso_date": "2026-07-03" }, { "slug": "overlay-network-ai-agents", @@ -78,7 +78,7 @@ "slug": "aegis-agent-firewall-prompt-injection", "title": "AEGIS: A Runtime Firewall for AI Agents Against Prompt Injection", "description": "AEGIS is an offline agent firewall on the Pilot app store. Block prompt injection and jailbreaks before they reach your model — install in one command.", - "date": "Jun 30", + "date": "Jun 25", "category": "Blog", "tags": [ "security", @@ -87,13 +87,13 @@ "agent-firewall" ], "banner": "banners/aegis-agent-firewall-prompt-injection.svg", - "iso_date": "2026-06-30" + "iso_date": "2026-06-25" }, { "slug": "ai-agent-app-store", "title": "The AI Agent App Store: Install Tools With One Command", "description": "How agents discover, install, and call tools on Pilot — the discover→install→call loop, signed local apps, and publishing your own to the agent app store.", - "date": "Jun 30", + "date": "Jun 27", "category": "Blog", "tags": [ "app-store", @@ -102,13 +102,13 @@ "mcp" ], "banner": "banners/ai-agent-app-store.svg", - "iso_date": "2026-06-30" + "iso_date": "2026-06-27" }, { "slug": "direct-communication-protocols-ai-agents-guide", "title": "AI agent communication protocols: Pilot vs MCP vs A2A vs ACP vs ANP", "description": "Compare AI agent communication protocols — MCP, A2A, ACP, ANP, and Pilot — on transport, discovery, NAT traversal, and trust. Find the right stack for your agents.", - "date": "Jun 30", + "date": "Jun 29", "category": "Blog", "tags": [ "comparison", @@ -119,13 +119,13 @@ "protocols" ], "banner": "banners/direct-communication-protocols-ai-agents-guide.svg", - "iso_date": "2026-06-30" + "iso_date": "2026-06-29" }, { "slug": "pilot-vs-tailscale-nebula-zerotier-ai-agents", "title": "Pilot vs Tailscale vs Nebula vs ZeroTier for AI Agents", "description": "Tailscale, Nebula, and ZeroTier are great machine VPNs — but agents need addressing, discovery, and per-peer trust. An honest architecture comparison and decision guide.", - "date": "Jun 28", + "date": "Jun 23", "category": "Blog", "tags": [ "comparison", @@ -134,103 +134,103 @@ "networking" ], "banner": "banners/pilot-vs-tailscale-nebula-zerotier-ai-agents.svg", - "iso_date": "2026-06-28" + "iso_date": "2026-06-23" }, { "slug": "secure-data-exchange-for-multi-cloud-ai-systems", "title": "Secure data exchange for multi-cloud AI systems", "description": "Discover essential strategies for explaining secure data exchange in multi-cloud AI systems. Learn to protect sensitive data effectively!", - "date": "May 11", + "date": "May 19", "category": "Blog", "tags": [ "blog" ], "banner": "banners/secure-data-exchange-for-multi-cloud-ai-systems.jpg", - "iso_date": "2026-05-11" + "iso_date": "2026-05-19" }, { "slug": "encrypted-data-exchange-for-decentralized-ai-systems", "title": "Encrypted Data Exchange for Decentralized AI", "description": "Unlock essential strategies with our guide to encrypted data exchange for decentralized AI systems, safeguarding sensitive data across networks.", - "date": "May 10", + "date": "May 17", "category": "Blog", "tags": [ "blog" ], "banner": "banners/encrypted-data-exchange-for-decentralized-ai-systems.jpg", - "iso_date": "2026-05-10" + "iso_date": "2026-05-17" }, { "slug": "legacy-protocol-integration-for-secure-distributed-ai", "title": "Legacy protocol integration for secure distributed AI", "description": "Unlock seamless connections with distributed AI by explaining legacy protocol integration. Discover modern strategies that simplify integration now!", - "date": "May 9", + "date": "May 15", "category": "Blog", "tags": [ "blog" ], "banner": "banners/legacy-protocol-integration-for-secure-distributed-ai.jpg", - "iso_date": "2026-05-09" + "iso_date": "2026-05-15" }, { "slug": "agent-communication-security-best-practices", "title": "Agent communication security: best practices for AI developers", "description": "Unlock essential agent communication security tips for AI developers. Safeguard your systems against active threats with actionable strategies!", - "date": "May 8", + "date": "May 13", "category": "Blog", "tags": [ "blog" ], "banner": "banners/agent-communication-security-best-practices.jpg", - "iso_date": "2026-05-08" + "iso_date": "2026-05-13" }, { "slug": "how-mutual-trust-secures-decentralized-ai-agent-networks", "title": "How mutual trust secures decentralized AI agent networks", "description": "Discover the crucial role of mutual trust in networks. Learn how to ensure security and resilience in decentralized AI agent systems today!", - "date": "May 6", + "date": "May 11", "category": "Blog", "tags": [ "blog" ], "banner": "banners/how-mutual-trust-secures-decentralized-ai-agent-networks.jpg", - "iso_date": "2026-05-06" + "iso_date": "2026-05-11" }, { "slug": "encryption-protocols-for-secure-ai-systems-a-practical-guide", "title": "Encryption protocols for secure AI systems: A practical guide", "description": "Discover essential encryption protocols in AI systems to secure your decentralized projects. Learn how to implement them effectively today!", - "date": "May 5", + "date": "May 9", "category": "Blog", "tags": [ "blog" ], "banner": "banners/encryption-protocols-for-secure-ai-systems-a-practical-guide.jpg", - "iso_date": "2026-05-05" + "iso_date": "2026-05-09" }, { "slug": "network-security-for-multi-agent-systems-key-strategies", "title": "Network security for multi-agent systems: Key strategies", "description": "Discover essential strategies for network security for multi-agent systems. Protect your AI systems with robust defense frameworks and protocols.", - "date": "May 4", + "date": "May 5", "category": "Blog", "tags": [ "blog" ], "banner": "banners/network-security-for-multi-agent-systems-key-strategies.jpg", - "iso_date": "2026-05-04" + "iso_date": "2026-05-05" }, { "slug": "why-direct-p2p-connections-power-secure-ai-networking", "title": "Why Direct P2P Connections Power Secure AI Networking", "description": "Discover why direct peer-to-peer connections are vital for secure AI networking. Learn how to enhance your agents' performance today!", - "date": "May 4", + "date": "May 7", "category": "Blog", "tags": [ "blog" ], "banner": "banners/why-direct-p2p-connections-power-secure-ai-networking.jpg", - "iso_date": "2026-05-04" + "iso_date": "2026-05-07" }, { "slug": "virtual-network-addresses-for-secure-decentralized-ai", @@ -248,37 +248,37 @@ "slug": "trustless-protocols-that-secure-decentralized-ai-systems", "title": "Trustless protocols that secure decentralized AI systems", "description": "Discover the crucial role of trustless protocols in securing decentralized AI systems, enhancing reliability and scalability for developers.", - "date": "May 2", + "date": "May 1", "category": "Blog", "tags": [ "blog" ], "banner": "banners/trustless-protocols-that-secure-decentralized-ai-systems.jpg", - "iso_date": "2026-05-02" + "iso_date": "2026-05-01" }, { "slug": "persistent-address-strategies-for-distributed-ai-systems", "title": "Persistent address strategies for distributed AI systems", "description": "Unlock the power of distributed AI with effective persistent address strategies. Discover how to optimize peer discovery and reduce operational debt.", - "date": "Apr 28", + "date": "Apr 29", "category": "Blog", "tags": [ "blog" ], "banner": "banners/persistent-address-strategies-for-distributed-ai-systems.jpg", - "iso_date": "2026-04-28" + "iso_date": "2026-04-29" }, { "slug": "ai-agent-discovery-process-p2p-networks", "title": "AI agent discovery: master P2P networks in 2026", "description": "Learn how to implement the AI agent discovery process step by step, from capability announcement to trust verification, for secure and scalable peer-to-peer networks.", - "date": "Apr 23", + "date": "Apr 21", "category": "Blog", "tags": [ "blog" ], "banner": "banners/ai-agent-discovery-process-p2p-networks.jpg", - "iso_date": "2026-04-23" + "iso_date": "2026-04-21" }, { "slug": "overlay-networking-secure-ai-agent-communication-explained", @@ -308,55 +308,55 @@ "slug": "github-com-alternatives-6", "title": "Top 6 GitHub.com Alternatives 2026", "description": "Discover 6 GitHub.com alternatives for secure collaboration in multi-cloud environments. Compare top options for effective development.", - "date": "Apr 24", + "date": "Apr 23", "category": "Blog", "tags": [ "blog" ], "banner": "banners/github-com-alternatives-6.jpg", - "iso_date": "2026-04-24" + "iso_date": "2026-04-23" }, { "slug": "persistent-network-addressing-secure-ai-systems", "title": "Persistent network addressing for secure AI systems", "description": "Learn how persistent network addressing works, where cloud environments fall short, and how to implement stable, secure addressing for decentralized AI systems.", - "date": "Apr 21", + "date": "Apr 17", "category": "Blog", "tags": [ "blog" ], "banner": "banners/persistent-network-addressing-secure-ai-systems.jpg", - "iso_date": "2026-04-21" + "iso_date": "2026-04-17" }, { "slug": "ai-agent-network-examples-secure-scalable-connectivity", "title": "Top AI agent network examples for secure, scalable connectivity", "description": "Explore top AI agent network examples including AgentNet, Google A2A, and ICP DeAI agents. Compare frameworks for secure, scalable, multi-cloud deployments.", - "date": "Apr 21", + "date": "Apr 19", "category": "Blog", "tags": [ "blog" ], "banner": "banners/ai-agent-network-examples-secure-scalable-connectivity.jpg", - "iso_date": "2026-04-21" + "iso_date": "2026-04-19" }, { "slug": "peer-to-peer-networking-examples-ai-engineers", "title": "Peer-to-peer networking examples every AI engineer should know", "description": "Explore real-world peer-to-peer networking examples including BitTorrent, libp2p, and IPFS, with practical guidance for AI engineers building secure distributed agent systems.", - "date": "Apr 17", + "date": "Apr 9", "category": "Blog", "tags": [ "blog" ], "banner": "banners/peer-to-peer-networking-examples-ai-engineers.jpg", - "iso_date": "2026-04-17" + "iso_date": "2026-04-09" }, { "slug": "userspace-tcp-over-udp-stack-pure-go", "title": "Building a Userspace TCP-over-UDP Stack in Pure Go", "description": "Sliding windows, Nagle's algorithm, RTO, and AES-GCM all in userspace, with zero third-party dependencies. How Pilot Protocol's transport layer works.", - "date": "Apr 19", + "date": "Apr 15", "category": "Engineering", "tags": [ "go", @@ -365,193 +365,193 @@ "systems" ], "banner": "banners/why-ai-agents-need-network-stack.webp", - "iso_date": "2026-04-19" + "iso_date": "2026-04-15" }, { "slug": "cloud-networking-secure-peer-to-peer-distributed-ai", "title": "Cloud networking: Secure peer-to-peer for distributed AI", "description": "Learn how cloud VPC and P2P protocols like libp2p and IPFS differ, why 87.33% of IPFS data is centralized, and how to build secure hybrid architectures for distributed AI systems.", - "date": "Apr 18", + "date": "Apr 13", "category": "Blog", "tags": [ "blog" ], "banner": "banners/cloud-networking-secure-peer-to-peer-distributed-ai.jpg", - "iso_date": "2026-04-18" + "iso_date": "2026-04-13" }, { "slug": "multi-cloud-networking-decentralized-ai-systems", "title": "Mastering multi-cloud networking for decentralized AI systems", "description": "Learn how to build secure multi-cloud networking for autonomous AI agents using overlays, SD-WAN, and zero-trust enclaves. Compare VPN, private interconnects, and agent-centric solutions.", - "date": "Apr 17", + "date": "Apr 11", "category": "Blog", "tags": [ "blog" ], "banner": "banners/multi-cloud-networking-decentralized-ai-systems.jpg", - "iso_date": "2026-04-17" + "iso_date": "2026-04-11" }, { "slug": "securing-ai-agent-networks-multi-cloud-environments", "title": "Securing AI agent networks in multi-cloud environments", "description": "Learn how to secure AI agent communications in multi-cloud environments using DIDs, Zero Trust, and blockchain-anchored frameworks like BlockA2A.", - "date": "Apr 16", + "date": "Apr 7", "category": "Blog", "tags": [ "blog" ], "banner": "banners/securing-ai-agent-networks-multi-cloud-environments.jpg", - "iso_date": "2026-04-16" + "iso_date": "2026-04-07" }, { "slug": "trust-network-protocols-secure-decentralized-systems", "title": "Trust in network protocols for decentralized systems", "description": "Learn how trust works in decentralized P2P and AI networks, covering EigenTrust, blockchain trust models, zero-trust principles, and dynamic trust evaluation for distributed systems.", - "date": "Apr 15", + "date": "Apr 5", "category": "Blog", "tags": [ "blog" ], "banner": "banners/trust-network-protocols-secure-decentralized-systems.jpg", - "iso_date": "2026-04-15" + "iso_date": "2026-04-05" }, { "slug": "persistent-addresses-distributed-autonomous-systems", "title": "Persistent Addresses for Distributed AI Agents", "description": "Learn how persistent addresses solve unstable endpoint problems in distributed and autonomous agent systems across multi-cloud environments with secure P2P solutions.", - "date": "Apr 14", + "date": "Aug 27", "category": "Blog", "tags": [ "blog" ], "banner": "banners/persistent-addresses-distributed-autonomous-systems.jpg", - "iso_date": "2026-04-14" + "iso_date": "2026-08-27" }, { "slug": "ai-networking-best-practices-secure-scalable-systems", "title": "AI networking best practices for secure, scalable systems", "description": "Learn proven AI networking best practices for secure, scalable agent systems using P2P architectures, encryption, and zero-trust security across multi-cloud environments.", - "date": "Apr 13", + "date": "Aug 25", "category": "Blog", "tags": [ "blog" ], "banner": "banners/ai-networking-best-practices-secure-scalable-systems.jpg", - "iso_date": "2026-04-13" + "iso_date": "2026-08-25" }, { "slug": "secure-ai-agent-networking-workflow-step-by-step", "title": "Secure AI agent networking workflow: step-by-step guide", "description": "Learn how to design a secure networking workflow for AI agents in multi-cloud environments, covering authentication, encrypted transport, NAT traversal, and hybrid protocol strategies.", - "date": "Apr 12", + "date": "Aug 23", "category": "Blog", "tags": [ "blog" ], "banner": "banners/secure-ai-agent-networking-workflow-step-by-step.jpg", - "iso_date": "2026-04-12" + "iso_date": "2026-08-23" }, { "slug": "autonomous-agent-networking-distributed-ai", "title": "Understanding autonomous agent networking for distributed AI", "description": "Learn how autonomous agent networking works, where architectures fail at scale, and which methodologies help AI developers build resilient decentralized agent systems.", - "date": "Apr 11", + "date": "Aug 21", "category": "Blog", "tags": [ "blog" ], "banner": "banners/autonomous-agent-networking-distributed-ai.jpg", - "iso_date": "2026-04-11" + "iso_date": "2026-08-21" }, { "slug": "network-tunnels-ai-secure-communication-autonomous-agents", "title": "Network tunnels in AI: Secure comms for autonomous agents", "description": "Learn how network tunnels in AI enable secure MCP server access for autonomous agents, covering protocols, security risks, Zero Trust practices, and implementation steps.", - "date": "Apr 10", + "date": "Aug 19", "category": "Blog", "tags": [ "blog" ], "banner": "banners/network-tunnels-ai-secure-communication-autonomous-agents.jpg", - "iso_date": "2026-04-10" + "iso_date": "2026-08-19" }, { "slug": "secure-communication-protocols-distributed-ai-systems", "title": "Secure communication protocols for distributed AI systems", "description": "Learn how to evaluate and implement secure communication protocols for distributed AI systems and autonomous agent networks, covering TLS 1.3, mTLS, WireGuard, and zero-trust architectures.", - "date": "Apr 8", + "date": "Aug 17", "category": "Blog", "tags": [ "blog" ], "banner": "banners/secure-communication-protocols-distributed-ai-systems.jpg", - "iso_date": "2026-04-08" + "iso_date": "2026-08-17" }, { "slug": "overlay-networking-automation-secure-ai-agent-solutions", "title": "Overlay networking for automation: Secure AI agent solutions", "description": "Learn how overlay networking for AI agent automation works, compare top tools like Cilium and Istio, and build secure zero-trust multi-cloud agent networks.", - "date": "Apr 7", + "date": "Aug 15", "category": "Blog", "tags": [ "blog" ], "banner": "banners/overlay-networking-automation-secure-ai-agent-solutions.jpg", - "iso_date": "2026-04-07" + "iso_date": "2026-08-15" }, { "slug": "encrypted-tunnel-advantages-peer-to-peer-ai-networks", "title": "Top encrypted tunnel advantages for P2P AI networks", "description": "Discover the top encrypted tunnel advantages for securing peer-to-peer AI agent networks across multi-cloud and NAT environments, with practical implementation guidance.", - "date": "Apr 6", + "date": "Aug 13", "category": "Blog", "tags": [ "blog" ], "banner": "banners/encrypted-tunnel-advantages-peer-to-peer-ai-networks.jpg", - "iso_date": "2026-04-06" + "iso_date": "2026-08-13" }, { "slug": "protocol-wrapping-secure-peer-to-peer-ai-systems", "title": "Protocol wrapping for secure peer-to-peer AI systems", "description": "Learn how protocol wrapping powers secure P2P AI networks. Covers VXLAN, Geneve, UDP overlays, anonymity wrappers, and real-world benchmarks for distributed systems engineers.", - "date": "Apr 5", + "date": "Aug 11", "category": "Blog", "tags": [ "blog" ], "banner": "banners/protocol-wrapping-secure-peer-to-peer-ai-systems.jpg", - "iso_date": "2026-04-05" + "iso_date": "2026-08-11" }, { "slug": "decentralized-networking-p2p-solutions-ai-architectures", "title": "Decentralized networking: P2P solutions for AI architectures", "description": "Learn how decentralized P2P networking protocols, NAT traversal, and mesh architectures enable secure, scalable communication for distributed AI systems and multi-cloud deployments.", - "date": "Apr 4", + "date": "Aug 9", "category": "Blog", "tags": [ "blog" ], "banner": "banners/decentralized-networking-p2p-solutions-ai-architectures.jpg", - "iso_date": "2026-04-04" + "iso_date": "2026-08-09" }, { "slug": "what-is-protocol-overlay-fundamentals-practical", "title": "What is protocol overlay? Fundamentals and practical insights", "description": "Learn what a protocol overlay is and how structured, unstructured, and hierarchical overlays improve peer-to-peer communication for distributed AI agent networks.", - "date": "Apr 3", + "date": "Aug 7", "category": "Blog", "tags": [ "blog" ], "banner": "banners/what-is-protocol-overlay-fundamentals-practical.jpg", - "iso_date": "2026-04-03" + "iso_date": "2026-08-07" }, { "slug": "scriptorium-replace-agentic-active-research-ready-intelligence", "title": "Scriptorium: Replace Agentic Active Research With Ready Intelligence", "description": "Scriptorium replaces the search-fetch-filter-compress agent research loop with a continuously updated, high-signal brief 92% fewer tokens, half the latency, identical decision quality.", - "date": "Apr 2", + "date": "Apr 3", "year": 2026, "category": "Blog", "tags": [ @@ -560,19 +560,19 @@ "scriptorium" ], "banner": "banners/scriptorium-replace-agentic-active-research-ready-intelligence.png", - "iso_date": "2026-04-02" + "iso_date": "2026-04-03" }, { "slug": "secure-network-infrastructure-ai-agents-practical-guide", "title": "Secure network infrastructure for AI agents: A practical guide", "description": "Learn how to build secure, decentralized network infrastructure for AI agents. Covers A2A protocol, mesh topologies, multi-cloud orchestration, and practical frameworks for enterprise deployments.", - "date": "Apr 2", + "date": "Aug 5", "category": "Blog", "tags": [ "blog" ], "banner": "banners/secure-network-infrastructure-ai-agents-practical-guide.jpg", - "iso_date": "2026-04-02" + "iso_date": "2026-08-05" }, { "slug": "ai-networking-terminology-a2a-mcp-anp-protocols", @@ -590,7 +590,7 @@ "slug": "enterprise-production-complete-identity-directory-audit-export", "title": "Enterprise Implementation Milestone: 99 Features, 234 Tests", "description": "A March 2026 implementation milestone for Pilot enterprise controls, including OIDC/JWT validation, directory mapping, blueprints, audit export, and early-access rollout boundaries.", - "date": "Mar 30", + "date": "Mar 29", "category": "Enterprise", "tags": [ "enterprise", @@ -600,25 +600,25 @@ "siem" ], "banner": "banners/enterprise-production-complete-identity-directory-audit-export.webp", - "iso_date": "2026-03-30" + "iso_date": "2026-03-29" }, { "slug": "decentralized-communication-protocols-ai-developers", "title": "Decentralized communication protocols for AI developers", "description": "Learn how to choose decentralized communication protocols for AI agent networks, covering NAT traversal, Kademlia DHT, E2EE, and practical stack selection.", - "date": "Mar 31", + "date": "Jul 29", "category": "Blog", "tags": [ "blog" ], "banner": "banners/decentralized-communication-protocols-ai-developers.jpg", - "iso_date": "2026-03-31" + "iso_date": "2026-07-29" }, { "slug": "connecting-mcp-servers-across-agents", "title": "Connecting MCP Servers to Agents Across Any Network", "description": "How to connect MCP-equipped agents across NATs, firewalls, and clouds. One command install, zero networking config. Go and Python examples.", - "date": "Mar 30", + "date": "Jul 23", "category": "Integration", "tags": [ "mcp", @@ -626,13 +626,13 @@ "networking" ], "banner": "banners/connecting-mcp-servers-across-agents.webp", - "iso_date": "2026-03-30" + "iso_date": "2026-07-23" }, { "slug": "peer-to-peer-agent-communication-no-server", "title": "Peer-to-Peer Agent Communication Without an Application Broker", "description": "Why hub-and-spoke can bottleneck agents. Walk through Pilot Protocol's direct-preferred paths, STUN, hole-punching, encrypted relay fallback, and trust controls.", - "date": "Mar 30", + "date": "Jul 25", "category": "Architecture", "tags": [ "p2p", @@ -640,43 +640,43 @@ "networking" ], "banner": "banners/peer-to-peer-agent-communication-no-server.webp", - "iso_date": "2026-03-30" + "iso_date": "2026-07-25" }, { "slug": "ai-networking-challenges-decentralized-systems", "title": "Top AI networking challenges for decentralized systems", "description": "Discover the 7 biggest AI networking challenges for decentralized and multi-cloud agent systems, with solution comparisons and practical guidance for engineers.", - "date": "Mar 30", + "date": "Aug 3", "category": "Blog", "tags": [ "blog" ], "banner": "banners/ai-networking-challenges-decentralized-systems.jpg", - "iso_date": "2026-03-30" + "iso_date": "2026-08-03" }, { "slug": "advanced-network-automation-tips-secure-ai-systems", "title": "Advanced network automation: 7 tips for secure AI systems", "description": "Discover 7 expert network automation strategies for secure, scalable multi-agent AI systems, covering scripting, APIs, NSoT, NETCONF, ML remediation, and IBN.", - "date": "Mar 29", + "date": "Aug 1", "category": "Blog", "tags": [ "blog" ], "banner": "banners/advanced-network-automation-tips-secure-ai-systems.jpg", - "iso_date": "2026-03-29" + "iso_date": "2026-08-01" }, { "slug": "multi-agent-system-networking-guide-ai-developers", "title": "Multi-agent system networking guide: 86.7% failure fix", "description": "Learn how to build secure, scalable multi-agent system networks. Covers architecture, protocols, benchmarking, and how to cut 86.7% failure rates in MAS.", - "date": "Mar 28", + "date": "Jul 21", "category": "Blog", "tags": [ "blog" ], "banner": "banners/multi-agent-system-networking-guide-ai-developers.jpg", - "iso_date": "2026-03-28" + "iso_date": "2026-07-21" }, { "slug": "enterprise-phase-3-rbac-policies-audit-fleet", @@ -725,7 +725,7 @@ "slug": "enterprise-private-networks-roadmap", "title": "Enterprise Private Networks: The Roadmap", "description": "Pilot Protocol is closing the gap between connectivity tool and enterprise infrastructure. SYN-level trust enforcement, tag-based policies, cascading revocation, and OIDC/SPIFFE identity integration.", - "date": "Mar 21", + "date": "Mar 23", "category": "Security", "tags": [ "enterprise", @@ -733,150 +733,150 @@ "roadmap" ], "banner": "banners/enterprise-private-networks-roadmap.webp", - "iso_date": "2026-03-21" + "iso_date": "2026-03-23" }, { "slug": "python-sdk-pilot-protocol", "title": "Announcing the Pilot Protocol Python SDK v0.1.1", "description": "Native Python bindings for Pilot Protocol. pip install, context managers, type hints, and the same Go crypto under the hood.", - "date": "Mar 13", + "date": "Mar 19", "category": "Integration", "tags": [ "python", "sdk" ], "banner": "banners/python-sdk-pilot-protocol.webp", - "iso_date": "2026-03-13" + "iso_date": "2026-03-19" }, { "slug": "build-openclaw-agent-self-organizes-pilot", "title": "Build an OpenClaw Agent That Self-Organizes Into a Pilot Network", "description": "Step-by-step tutorial: build a Python agent that autonomously joins the Pilot network, discovers peers, establishes trust, accepts tasks, and builds reputation.", - "date": "Mar 11", + "date": "Jul 19", "category": "Tutorial", "tags": [ "openclaw", "autonomous" ], "banner": "banners/build-openclaw-agent-self-organizes-pilot.webp", - "iso_date": "2026-03-11" + "iso_date": "2026-07-19" }, { "slug": "preferential-attachment-ai-networks-trust-graph", "title": "Why a Few AI Agents Get 80% of the Work (And How to Stop It)", "description": "Autonomous agent networks follow the same winner-take-all dynamics as social networks. Here's the power-law data and how to design against hub collapse.", - "date": "Mar 10", + "date": "Jul 17", "category": "AI/ML", "tags": [ "openclaw", "graph-theory" ], "banner": "banners/preferential-attachment-ai-networks-trust-graph.webp", - "iso_date": "2026-03-10" + "iso_date": "2026-07-17" }, { "slug": "openclaw-agents-behind-nat-zero-config", "title": "OpenClaw Agents Behind NAT: Zero-Config Peer Connectivity", "description": "52% of OpenClaw agents were behind NAT. None configured port forwarding. How Pilot Protocol's three-tier traversal delivers zero-config connectivity for autonomous agents.", - "date": "Mar 9", + "date": "Mar 17", "category": "Guide", "tags": [ "openclaw", "NAT" ], "banner": "banners/openclaw-agents-behind-nat-zero-config.webp", - "iso_date": "2026-03-09" + "iso_date": "2026-03-17" }, { "slug": "scaling-openclaw-fleets-thousands-agents", "title": "Scaling OpenClaw Fleets: Running Thousands of Autonomous Agents", "description": "Operational guide to running large OpenClaw fleets on Pilot Protocol: registry capacity, daemon resources, systemd deployment, monitoring, and bottlenecks at scale.", - "date": "Mar 8", + "date": "Mar 15", "category": "Operations", "tags": [ "openclaw", "scale" ], "banner": "banners/scaling-openclaw-fleets-thousands-agents.webp", - "iso_date": "2026-03-08" + "iso_date": "2026-03-15" }, { "slug": "clawhub-to-live-network-openclaw-discovery", "title": "From ClawHub to Live Network: How OpenClaw Agents Discover Peers", "description": "The complete journey from clawhub install to live network participation: STUN discovery, registration, tag search, and trust negotiation.", - "date": "Mar 7", + "date": "Mar 13", "category": "Guide", "tags": [ "openclaw", "discovery" ], "banner": "banners/clawhub-to-live-network-openclaw-discovery.webp", - "iso_date": "2026-03-07" + "iso_date": "2026-03-13" }, { "slug": "multi-agent-pipelines-openclaw-encrypted-tunnels", "title": "Multi-Agent Pipelines: Chaining OpenClaw Agents Over Encrypted Tunnels", "description": "Build multi-agent pipelines with OpenClaw and Pilot Protocol: two-agent chains, fan-out parallelism, event-driven stages, conditional routing, and dynamic discovery.", - "date": "Mar 6", + "date": "Mar 11", "category": "Architecture", "tags": [ "openclaw", "pipelines" ], "banner": "banners/multi-agent-pipelines-openclaw-encrypted-tunnels.webp", - "iso_date": "2026-03-06" + "iso_date": "2026-03-11" }, { "slug": "sociology-of-machines-626-agents", "title": "The Sociology of Machines: What 626 Agents Taught Us", "description": "Autonomous AI agents form social structures identical to human networks: preferential attachment, triadic closure, Dunbar scaling. A new domain of machine sociology.", - "date": "Mar 5", + "date": "Mar 9", "category": "AI/ML", "tags": [ "openclaw", "sociology" ], "banner": "banners/sociology-of-machines-626-agents.webp", - "iso_date": "2026-03-05" + "iso_date": "2026-03-09" }, { "slug": "building-custom-pilot-skills-openclaw", "title": "Building Custom Pilot Skills for OpenClaw Agents", "description": "How to create, structure, and publish custom Pilot Protocol skills on ClawHub. Error handling, workflow design, and runtime context for autonomous agents.", - "date": "Mar 4", + "date": "Mar 7", "category": "Tutorial", "tags": [ "openclaw", "skills" ], "banner": "banners/building-custom-pilot-skills-openclaw.webp", - "iso_date": "2026-03-04" + "iso_date": "2026-03-07" }, { "slug": "emergent-trust-networks-agents-choose-peers", "title": "Emergent Trust Networks: When Agents Choose Their Peers", "description": "Agents made thousands of independent trust decisions. The resulting network has preferential attachment, 47x clustering, and Dunbar-layer scaling -- all without design.", - "date": "Mar 3", + "date": "Mar 5", "category": "AI/ML", "tags": [ "openclaw", "trust" ], "banner": "banners/emergent-trust-networks-agents-choose-peers.webp", - "iso_date": "2026-03-03" + "iso_date": "2026-03-05" }, { "slug": "why-autonomous-agents-need-private-discovery", "title": "Why Autonomous Agents Need Private-by-Default Discovery", "description": "Public discovery is dangerous for unsupervised AI agents. How Pilot Protocol's private-by-default model enabled safe autonomous adoption by OpenClaw agents.", - "date": "Mar 2", + "date": "Mar 3", "category": "Security", "tags": [ "openclaw", "privacy" ], "banner": "banners/why-autonomous-agents-need-private-discovery.webp", - "iso_date": "2026-03-02" + "iso_date": "2026-03-03" }, { "slug": "openclaw-meets-pilot-agent-networking-one-command", @@ -895,454 +895,454 @@ "slug": "how-626-agents-autonomously-adopted-pilot", "title": "How 626 Agents Autonomously Adopted a Network Protocol", "description": "The story of how OpenClaw agents independently discovered, installed, and formed a trust network on Pilot Protocol -- without any human direction.", - "date": "Feb 28", + "date": "Jul 13", "category": "AI/ML", "tags": [ "openclaw", "research" ], "banner": "banners/how-626-agents-autonomously-adopted-pilot.webp", - "iso_date": "2026-02-28" + "iso_date": "2026-07-13" }, { "slug": "federated-learning-p2p-communication", "title": "P2P Communication for Federated Learning Nodes", "description": "gRPC adds 200ms per round. Federated learning spends 58-93% of time on communication. Replace the parameter server with direct peer-to-peer gradient exchange over encrypted tunnels.", - "date": "Feb 28", + "date": "Jun 11", "category": "AI/ML", "tags": [ "federated-learning", "P2P" ], "banner": "banners/federated-learning-p2p-communication.webp", - "iso_date": "2026-02-28" + "iso_date": "2026-06-11" }, { "slug": "chain-ai-models-across-machines", "title": "Chain AI Models Across Machines With Persistent Tunnels", "description": "Multi-model pipelines lose 25-75% throughput to per-request HTTP overhead. Persistent tunnels connect once, stream continuously, and eliminate connection setup latency.", - "date": "Feb 28", + "date": "Jun 15", "category": "AI/ML", "tags": [ "model-chaining", "pipelines" ], "banner": "banners/chain-ai-models-across-machines.webp", - "iso_date": "2026-02-28" + "iso_date": "2026-06-15" }, { "slug": "distributed-rag-without-central-knowledge-base", "title": "Distributed RAG Without a Central Knowledge Base", "description": "Centralizing all documents in one vector database violates data ownership. Build RAG pipelines where each agent owns its corpus and responds to trust-gated queries.", - "date": "Feb 27", + "date": "Jun 13", "category": "AI/ML", "tags": [ "RAG", "privacy" ], "banner": "banners/distributed-rag-without-central-knowledge-base.webp", - "iso_date": "2026-02-27" + "iso_date": "2026-06-13" }, { "slug": "move-beyond-rest-persistent-connections-for-agents", "title": "Beyond REST: Persistent Connections for AI Agents", "description": "REST polling wastes 98.5% of requests. WebSockets break at scale. Persistent bidirectional connections solve real-time agent communication without the infrastructure pain.", - "date": "Feb 26", + "date": "Jul 7", "category": "Architecture", "tags": [ "REST", "real-time" ], "banner": "banners/move-beyond-rest-persistent-connections-for-agents.webp", - "iso_date": "2026-02-26" + "iso_date": "2026-07-07" }, { "slug": "lightweight-swarm-communication-drones-robots", "title": "Lightweight Swarm Communication for Drones and Robots", "description": "ROS2/DDS multicast storms kill WiFi. MAVLink has no encryption. A single 10MB binary gives robot swarms encrypted pub/sub, NAT traversal, and tag-based discovery.", - "date": "Feb 25", + "date": "Jun 21", "category": "Guide", "tags": [ "drones", "swarm" ], "banner": "banners/lightweight-swarm-communication-drones-robots.webp", - "iso_date": "2026-02-25" + "iso_date": "2026-06-21" }, { "slug": "smart-home-without-cloud-local-device-communication", "title": "Smart Home Without Cloud: Local-First Device Communication", "description": "Insteon died overnight, Wemo cloud ended in 2026, Google IoT Core shut down. Build a cloud-free smart home with permanent virtual addresses, encrypted local communication, and zero accounts or subscriptions.", - "date": "Feb 25", + "date": "Jun 19", "category": "Guide", "tags": [ "smart-home", "local-first" ], "banner": "banners/smart-home-without-cloud-local-device-communication.webp", - "iso_date": "2026-02-25" + "iso_date": "2026-06-19" }, { "slug": "build-ai-agent-marketplace-discovery-reputation", "title": "Build an AI Agent Marketplace With Discovery and Reputation", "description": "Solve the ghost agent problem. Tag-based capability discovery, cryptographic trust handshakes, and behavior-based reputation create a self-regulating agent marketplace without a centralized platform.", - "date": "Feb 24", + "date": "Jul 11", "category": "Architecture", "tags": [ "marketplace", "discovery" ], "banner": "banners/build-ai-agent-marketplace-discovery-reputation.webp", - "iso_date": "2026-02-24" + "iso_date": "2026-07-11" }, { "slug": "distributed-monitoring-without-prometheus", "title": "Distributed Monitoring Without Prometheus or Grafana", "description": "One binary per node, shell scripts for metrics, encrypted pub/sub for delivery. Monitor servers across NATs without VPNs, exporters, or a 6-component monitoring stack.", - "date": "Feb 24", + "date": "Jun 17", "category": "Operations", "tags": [ "monitoring", "event-stream" ], "banner": "banners/distributed-monitoring-without-prometheus.webp", - "iso_date": "2026-02-24" + "iso_date": "2026-06-17" }, { "slug": "secure-research-collaboration-share-models-not-data", "title": "Secure Research Collaboration: Share Models, Not Data", "description": "Cross-institutional ML collaboration without centralizing raw data. Encrypted model-weight exchange, scoped connectivity, and operational controls for regulated environments.", - "date": "Feb 23", + "date": "Jun 9", "category": "AI/ML", "tags": [ "privacy", "federated-learning" ], "banner": "banners/secure-research-collaboration-share-models-not-data.webp", - "iso_date": "2026-02-23" + "iso_date": "2026-06-09" }, { "slug": "secure-ai-agent-communication-zero-trust", "title": "How to Secure AI Agent Communication With Zero Trust", "description": "Zero trust for AI agents: Ed25519 identity, private-by-default discovery, mutual handshakes with justification, and instant revocation. CrewAI exfiltrated data 65% of the time -- here is how to stop trusting by default.", - "date": "Feb 23", + "date": "Jun 5", "category": "Security", "tags": [ "zero-trust", "identity" ], "banner": "banners/secure-ai-agent-communication-zero-trust.webp", - "iso_date": "2026-02-23" + "iso_date": "2026-06-05" }, { "slug": "how-ai-agents-discover-each-other", "title": "How AI Agents Discover Each Other on a Live Network", "description": "Agent discovery without manual config files. Registry-based hostname lookup, tag-based capability search, and runtime self-discovery.", - "date": "Feb 22", + "date": "May 25", "category": "Guide", "tags": [ "discovery", "registry" ], "banner": "banners/how-ai-agents-discover-each-other.webp", - "iso_date": "2026-02-22" + "iso_date": "2026-05-25" }, { "slug": "connect-ai-agents-behind-nat-without-vpn", "title": "Connect AI Agents Behind NAT Without a VPN", "description": "88% of networks involve NAT. Pilot's three-tier traversal -- STUN, hole-punching, relay -- connects agents behind any firewall automatically. No VPN, no port forwarding, no ngrok.", - "date": "Feb 22", + "date": "May 27", "category": "Guide", "tags": [ "NAT", "P2P" ], "banner": "banners/connect-ai-agents-behind-nat-without-vpn.webp", - "iso_date": "2026-02-22" + "iso_date": "2026-05-27" }, { "slug": "run-agent-network-without-cloud-dependency", "title": "Run Your Agent Network Without Cloud Dependency", "description": "Insteon, Wemo, Google IoT Core -- cloud services shut down and devices become paperweights. Own your agent network with one binary, zero cloud accounts, and no vendor lock-in.", - "date": "Feb 21", + "date": "May 29", "category": "Guide", "tags": [ "independence", "IoT" ], "banner": "banners/run-agent-network-without-cloud-dependency.webp", - "iso_date": "2026-02-21" + "iso_date": "2026-05-29" }, { "slug": "replace-webhooks-with-persistent-agent-tunnels", "title": "Replace Webhooks With Persistent Agent Tunnels", "description": "Webhooks fail silently, require public URLs, and create distributed systems problems. Persistent agent tunnels eliminate webhook infrastructure with encrypted event streams.", - "date": "Feb 21", + "date": "Jul 9", "category": "Architecture", "tags": [ "webhooks", "event-stream" ], "banner": "banners/replace-webhooks-with-persistent-agent-tunnels.webp", - "iso_date": "2026-02-21" + "iso_date": "2026-07-09" }, { "slug": "cross-company-agent-collaboration-without-shared-infrastructure", "title": "Cross-Company Agent Collaboration Without a Shared App Broker", "description": "Enable B2B agent collaboration with scoped trust handshakes and encrypted tunnels without provisioning a workflow-specific broker. How Pilot complements A2A and MCP as the transport layer.", - "date": "Feb 20", + "date": "Jun 3", "category": "Architecture", "tags": [ "B2B", "interoperability" ], "banner": "banners/cross-company-agent-collaboration-without-shared-infrastructure.webp", - "iso_date": "2026-02-20" + "iso_date": "2026-06-03" }, { "slug": "hipaa-compliant-agent-communication", "title": "Technical Controls for Healthcare AI Agent Communication", "description": "How encrypted tunnels, peer trust, and network audit events can support a healthcare AI security architecture, with clear boundaries for operator responsibilities.", - "date": "Feb 20", + "date": "Jun 7", "category": "Security", "tags": [ "HIPAA", "healthcare" ], "banner": "banners/hipaa-compliant-agent-communication.webp", - "iso_date": "2026-02-20" + "iso_date": "2026-06-07" }, { "slug": "connect-agents-across-aws-gcp-azure-without-vpn", "title": "Connect AI Agents Across AWS, GCP & Azure Without a VPN", "description": "Deploy agents across any cloud with two commands. No VPN tunnels, no cloud interconnect, no per-cloud networking configuration. Virtual addresses that work everywhere.", - "date": "Feb 19", + "date": "Jun 1", "category": "Guide", "tags": [ "multi-cloud", "deployment" ], "banner": "banners/connect-agents-across-aws-gcp-azure-without-vpn.webp", - "iso_date": "2026-02-19" + "iso_date": "2026-06-01" }, { "slug": "how-pilot-protocol-works", "title": "How Pilot Protocol Works", "description": "A deep dive into 48-bit virtual addresses, UDP tunnels, three-tier NAT traversal, X25519-based tunnel encryption, and policy-gated endpoint access.", - "date": "Feb 19", + "date": "May 21", "category": "Architecture", "tags": [ "deep-dive", "networking" ], "banner": "banners/how-pilot-protocol-works.webp", - "iso_date": "2026-02-19" + "iso_date": "2026-05-21" }, { "slug": "build-multi-agent-network-five-minutes", "title": "Build a Multi-Agent Network in 5 Minutes", "description": "From install to working demo. Start two agents, establish trust, send messages, transfer files, and run benchmarks in under 5 minutes.", - "date": "Feb 18", + "date": "Feb 28", "category": "Tutorial", "tags": [ "quickstart", "getting-started" ], "banner": "banners/build-multi-agent-network-five-minutes.webp", - "iso_date": "2026-02-18" + "iso_date": "2026-02-28" }, { "slug": "why-ai-agents-need-network-stack", "title": "Why AI Agents Need Their Own Network Stack", "description": "A2A assumes HTTP endpoints. MCP assumes reachable servers. 88% of networks involve NAT. The agent ecosystem is missing its TCP/IP layer.", - "date": "Feb 17", + "date": "Feb 2", "category": "Architecture", "tags": [ "opinion", "ai-agents" ], "banner": "banners/why-ai-agents-need-network-stack.webp", - "iso_date": "2026-02-17" + "iso_date": "2026-02-02" }, { "slug": "trust-model-agents-invisible-by-default", "title": "The Pilot Protocol Trust Model: Why Agents Should Be Invisible by Default", "description": "Private-by-default agent discovery, Ed25519 mutual handshakes, instant revocation, and why this is the opposite of A2A Agent Cards.", - "date": "Feb 17", + "date": "Feb 10", "category": "Security", "tags": [ "trust", "privacy" ], "banner": "banners/trust-model-agents-invisible-by-default.webp", - "iso_date": "2026-02-17" + "iso_date": "2026-02-10" }, { "slug": "benchmarking-http-vs-udp-overlay", "title": "Benchmarking Agent Communication: HTTP vs. UDP Overlay", "description": "Hard numbers comparing connection setup, message latency, throughput, and memory usage between HTTP/2, gRPC, WebSocket, and Pilot Protocol.", - "date": "Feb 16", + "date": "Feb 26", "category": "Architecture", "tags": [ "performance", "data" ], "banner": "banners/benchmarking-http-vs-udp-overlay.webp", - "iso_date": "2026-02-16" + "iso_date": "2026-02-26" }, { "slug": "build-agent-swarm-self-organizes", "title": "Build an Agent Swarm That Self-Organizes via Reputation", "description": "10 agents that discover peers, establish trust, delegate tasks, execute with LLMs, and build reputation. No orchestrator. The swarm self-organizes.", - "date": "Feb 16", + "date": "May 23", "category": "Tutorial", "tags": [ "swarm" ], "banner": "banners/build-agent-swarm-self-organizes.webp", - "iso_date": "2026-02-16" + "iso_date": "2026-05-23" }, { "slug": "replace-message-broker-twelve-lines-go", "title": "Replace Your Agent Message Broker with 12 Lines of Go", "description": "Build event-driven agent architectures without Kafka, RabbitMQ, or Redis. Pilot's built-in pub/sub handles topic routing, wildcard subscriptions, and persistent connections.", - "date": "Feb 15", + "date": "Feb 24", "category": "Tutorial", "tags": [ "pub-sub", "go" ], "banner": "banners/replace-message-broker-twelve-lines-go.webp", - "iso_date": "2026-02-15" + "iso_date": "2026-02-24" }, { "slug": "http-services-over-encrypted-overlay", "title": "Run HTTP Services Over an Encrypted Agent Overlay", "description": "Standard Go HTTP servers running on Pilot ports. Gateway exposes them as local IPs. REST API mesh with automatic encryption, zero TLS configuration.", - "date": "Feb 15", + "date": "Feb 22", "category": "Tutorial", "tags": [ "http", "gateway" ], "banner": "banners/http-services-over-encrypted-overlay.webp", - "iso_date": "2026-02-15" + "iso_date": "2026-02-22" }, { "slug": "peer-to-peer-file-transfer-agents", "title": "Peer-to-Peer File Transfer Between AI Agents (No S3 Required)", "description": "Direct agent-to-agent file transfer over encrypted tunnels. Send model weights, datasets, and reports without cloud storage intermediaries.", - "date": "Feb 14", + "date": "Feb 20", "category": "Tutorial", "tags": [ "file-transfer", "p2p" ], "banner": "banners/peer-to-peer-file-transfer-agents.webp", - "iso_date": "2026-02-14" + "iso_date": "2026-02-20" }, { "slug": "nat-traversal-ai-agents-deep-dive", "title": "NAT Traversal for AI Agents: A Deep Dive", "description": "STUN discovery, UDP hole-punching, relay fallback, and beacon gossip. The definitive reference on making agents reachable through any NAT type.", - "date": "Feb 13", + "date": "Feb 6", "category": "Guide", "tags": [ "nat", "networking" ], "banner": "banners/nat-traversal-ai-agents-deep-dive.webp", - "iso_date": "2026-02-13" + "iso_date": "2026-02-06" }, { "slug": "a2a-agent-cards-over-pilot-tunnels", "title": "Building A2A Agent Cards Over Pilot Protocol Tunnels", "description": "Run Google's A2A protocol over Pilot's encrypted tunnels. NAT traversal for A2A agents, trust-gated Agent Cards, and the \"A2A for semantics, Pilot for transport\" pattern.", - "date": "Feb 13", + "date": "Feb 16", "category": "Integration", "tags": [ "a2a", "google" ], "banner": "banners/a2a-agent-cards-over-pilot-tunnels.webp", - "iso_date": "2026-02-13" + "iso_date": "2026-02-16" }, { "slug": "zero-dependency-encryption-x25519-aes-gcm", "title": "Zero-Dependency Agent Encryption: X25519 + AES-256-GCM in Pure Go", "description": "How Pilot implements authenticated key exchange, tunnel encryption, nonce management, and replay protection using only Go's standard library.", - "date": "Feb 12", + "date": "Feb 8", "category": "Security", "tags": [ "security", "go" ], "banner": "banners/zero-dependency-encryption-x25519-aes-gcm.webp", - "iso_date": "2026-02-12" + "iso_date": "2026-02-08" }, { "slug": "private-agent-network-company", "title": "Building a Private Agent Network for Your Company", "description": "Set up a private Pilot network, enroll agents, configure trust policies, bridge legacy systems via gateway, and monitor with the built-in dashboard.", - "date": "Feb 11", + "date": "Feb 12", "category": "Guide", "tags": [ "enterprise", "deployment" ], "banner": "banners/private-agent-network-company.webp", - "iso_date": "2026-02-11" + "iso_date": "2026-02-12" }, { "slug": "pilot-vs-tcp-grpc-nats-comparison", "title": "Pilot vs. TCP vs. gRPC vs. NATS: Agent Communication", "description": "An honest comparison with real benchmarks. Where each wins, where each loses, and which to use for your agent architecture.", - "date": "Feb 11", + "date": "Feb 4", "category": "Architecture", "tags": [ "grpc", "nats" ], "banner": "banners/pilot-vs-tcp-grpc-nats-comparison.webp", - "iso_date": "2026-02-11" + "iso_date": "2026-02-04" }, { "slug": "contributing-codebase-tour", "title": "Contributing to Pilot Protocol: A Tour of the Codebase", "description": "Package map, test environment, how to add a new service, linter gotchas, and good first issues for new contributors.", - "date": "Feb 10", + "date": "Feb 18", "category": "Guide", "tags": [ "contributing", "open-source" ], "banner": "banners/contributing-codebase-tour.webp", - "iso_date": "2026-02-10" + "iso_date": "2026-02-18" }, { "slug": "mcp-plus-pilot-tools-and-network", "title": "MCP + Pilot: Tools and a Network for AI Agents", "description": "MCP handles tool access. Pilot handles peer communication. Together: agents that gather data, share results, and delegate work without a platform in the middle.", - "date": "Feb 9", + "date": "Feb 14", "category": "Integration", "tags": [ "mcp", "anthropic" ], "banner": "banners/mcp-plus-pilot-tools-and-network.webp", - "iso_date": "2026-02-09" + "iso_date": "2026-02-14" }, { "slug": "claude-agent-teams-over-pilot", "title": "Building Claude Code Agent Teams Over Pilot Protocol", "description": "Distributed specialist agents across machines and networks. Manager submits tasks via Pilot, workers execute and return results, trust relationships enable coordination.", - "date": "Feb 9", + "date": "Jul 15", "category": "Integration", "tags": [ "claude", "agent-teams" ], "banner": "banners/claude-agent-teams-over-pilot.webp", - "iso_date": "2026-02-09" + "iso_date": "2026-07-15" } ] diff --git a/src/data/blogPosts.ts b/src/data/blogPosts.ts index e2f4413b..a0a952f3 100644 --- a/src/data/blogPosts.ts +++ b/src/data/blogPosts.ts @@ -12,7 +12,9 @@ export interface BlogPost { iso_date?: string; } -export const allPosts: BlogPost[] = data as BlogPost[]; +export const allPosts: BlogPost[] = [...(data as BlogPost[])].sort( + (a, b) => (b.iso_date || '').localeCompare(a.iso_date || ''), +); export const companyNews = allPosts.filter((post) => post.category === 'Company'); export const blogPosts = allPosts.filter((post) => post.category !== 'Company'); diff --git a/src/data/learnGuides.ts b/src/data/learnGuides.ts index f4477c9e..4dea81a1 100644 --- a/src/data/learnGuides.ts +++ b/src/data/learnGuides.ts @@ -3,6 +3,7 @@ export interface LearnGuide { title: string; description: string; date: string; + isoDate: string; track: 'Foundations' | 'Transport' | 'Security'; } @@ -12,6 +13,7 @@ export const learnGuides: LearnGuide[] = [ title: 'What Is Pilot Protocol?', description: 'A system-level introduction to persistent agent addresses, encrypted peer tunnels, discovery, trust, and installable capabilities.', date: 'July 30, 2026', + isoDate: '2026-07-30', track: 'Foundations', }, { @@ -19,6 +21,7 @@ export const learnGuides: LearnGuide[] = [ title: 'What Makes a Pilot Agent?', description: 'The identity, daemon, address, trust relationship, and application boundary that turn an existing agent into a network participant.', date: 'July 22, 2026', + isoDate: '2026-07-22', track: 'Foundations', }, { @@ -26,6 +29,7 @@ export const learnGuides: LearnGuide[] = [ title: 'AI Networking Across Multiple Clouds', description: 'How agent connectivity changes when workloads span cloud accounts, edge devices, laptops, and organizational boundaries.', date: 'July 24, 2026', + isoDate: '2026-07-24', track: 'Foundations', }, { @@ -33,6 +37,7 @@ export const learnGuides: LearnGuide[] = [ title: 'gRPC and UDP Transport Options', description: 'A precise look at gRPC transport assumptions, UDP overlays, and where each layer belongs in an agent communication stack.', date: 'July 23, 2026', + isoDate: '2026-07-23', track: 'Transport', }, { @@ -40,6 +45,7 @@ export const learnGuides: LearnGuide[] = [ title: 'NATS vs. gRPC for Agent Messaging', description: 'Compare connectivity models, messaging patterns, deployment requirements, and the role of an overlay beneath either option.', date: 'July 23, 2026', + isoDate: '2026-07-23', track: 'Transport', }, { @@ -47,6 +53,7 @@ export const learnGuides: LearnGuide[] = [ title: 'MCP Tunnels vs. VPNs for Agents', description: 'Separate tool access, network reachability, identity, and authorization so similarly named approaches are evaluated on the right boundary.', date: 'July 25, 2026', + isoDate: '2026-07-25', track: 'Transport', }, { @@ -54,6 +61,7 @@ export const learnGuides: LearnGuide[] = [ title: 'How Network Agent Tokens Differ', description: 'Compare an agent cryptographic identity with API keys, bearer tokens, and application-level credentials without collapsing the layers.', date: 'July 22, 2026', + isoDate: '2026-07-22', track: 'Security', }, { @@ -61,6 +69,7 @@ export const learnGuides: LearnGuide[] = [ title: 'How X25519 Secures Agent Communication', description: 'Understand key agreement, tunnel secrets, authenticated encryption, and the limits of what transport cryptography can authorize.', date: 'July 24, 2026', + isoDate: '2026-07-24', track: 'Security', }, ]; diff --git a/src/data/solutions.ts b/src/data/solutions.ts index cd2d9961..042954dc 100644 --- a/src/data/solutions.ts +++ b/src/data/solutions.ts @@ -346,7 +346,7 @@ export const solutions: SolutionProfile[] = [ value: '40%', body: 'is the average share of a seller’s week spent selling, according to a survey of more than four thousand sales professionals.', source: 'Salesforce State of Sales 2026', - href: 'https://www.salesforce.com/news/stories/state-of-sales-report-announcement-2026/', + href: 'https://www.salesforce.com/sales/state-of-sales/', }, problemTitle: 'Prospecting work is spread across too many disconnected tools.', problemBody: 'A useful account brief can require company enrichment, people data, public web research, internal context, drafting, and channel follow-up. Each handoff adds another copy-and-paste boundary. Pilot lets a team compose these steps through typed apps while retaining the option to substitute a capability as the workflow evolves.', diff --git a/src/layouts/BlogLayout.astro b/src/layouts/BlogLayout.astro index 14f6c2e9..f9ed94f0 100644 --- a/src/layouts/BlogLayout.astro +++ b/src/layouts/BlogLayout.astro @@ -5,6 +5,7 @@ import Footer from '../components/Footer.astro'; import Breadcrumbs from '../components/Breadcrumbs.astro'; import articleImageManifest from '../data/articleImageManifest.json'; import { allPosts, blogPosts, companyNews } from '../data/blogPosts'; +import { learnGuides } from '../data/learnGuides'; import { getBlogImage } from '../lib/blogImages'; import '../styles/global.css'; import '../styles/system.css'; @@ -41,7 +42,15 @@ const pathParts = Astro.url.pathname.replace(/\/$/, '').split('/'); const currentSlug = pathParts[pathParts.length - 1].replace('.html', ''); const currentIndex = collectionPosts.findIndex(p => p.slug === currentSlug); const currentPost = allPosts.find(p => p.slug === currentSlug); -const publishedAt = currentPost?.iso_date || date; +const currentGuide = isLearn ? learnGuides.find((guide) => guide.slug === currentSlug) : undefined; +const learnGuideIndex = currentGuide ? learnGuides.findIndex((guide) => guide.slug === currentSlug) : -1; +const learnRelated = currentGuide + ? learnGuides + .filter((guide) => guide.slug !== currentSlug) + .sort((a, b) => Number(b.track === currentGuide.track) - Number(a.track === currentGuide.track)) + .slice(0, 3) + : []; +const publishedAt = currentPost?.iso_date || currentGuide?.isoDate || date; const modifiedAt = dateModified || publishedAt; const articleAuthor = author || { name: 'Pilot Protocol editorial team', @@ -49,8 +58,12 @@ const articleAuthor = author || { type: 'Organization' as const, }; -const prevPost = currentIndex > 0 ? collectionPosts[currentIndex - 1] : null; -const nextPost = currentIndex >= 0 && currentIndex < collectionPosts.length - 1 ? collectionPosts[currentIndex + 1] : null; +const prevPost = isLearn + ? (learnGuideIndex >= 0 ? learnGuides[(learnGuideIndex - 1 + learnGuides.length) % learnGuides.length] : null) + : (currentIndex > 0 ? collectionPosts[currentIndex - 1] : null); +const nextPost = isLearn + ? (learnGuideIndex >= 0 ? learnGuides[(learnGuideIndex + 1) % learnGuides.length] : null) + : (currentIndex >= 0 && currentIndex < collectionPosts.length - 1 ? collectionPosts[currentIndex + 1] : null); const currentTags = new Set(tags.map(t => t.toLowerCase())); const related = collectionPosts @@ -191,7 +204,7 @@ const faqSectionId = headingIds.has('frequently-asked-questions')

{title}

@@ -236,7 +249,7 @@ const faqSectionId = headingIds.has('frequently-asked-questions') {post.title} ); @@ -246,6 +259,26 @@ const faqSectionId = headingIds.has('frequently-asked-questions') )} + {learnRelated.length > 0 && ( + + )} + {(prevPost || nextPost) && (