/** * Agentify.Help — Public Cookbook Site * * "Build the AI expert. Once. Right." * * One-per-person registry. Corpus-grounded. Framework-distilled. Steward-named. * A civic project under WellSpr.ing covenant. Published April 24, 2026. * * Domain: agentify.help (Bunny DNS → Fly.io) * Same stack pattern as notgit.org — standalone SSR HTML, domain-keyed. */ import express from "express"; import type { Express, Request, Response } from "express"; import fs from "fs"; import path from "path"; import { pool } from "../db"; import { getOgPng } from "../og-images"; import { Resend } from "resend"; import crypto from "crypto"; const resend = new Resend(process.env.RESEND_API_KEY); const ADMIN_KEY = process.env.ADMIN_KEY || "b0db7a87384fc814b0f46ea7bdc6ab6a81152be5b098718b"; // ── DB setup ────────────────────────────────────────────────────────────────── async function ensureAgentifyHelpTables() { await pool.query(` CREATE TABLE IF NOT EXISTS agentify_subject_registry ( id SERIAL PRIMARY KEY, subject_slug TEXT UNIQUE NOT NULL, subject_name TEXT NOT NULL, subject_domain TEXT, steward_name TEXT NOT NULL, steward_email TEXT NOT NULL, host_url TEXT, corpus_version TEXT DEFAULT '1.0.0', status TEXT NOT NULL DEFAULT 'pending', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) `); // Additive migrations — idempotent await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS registered_via TEXT NOT NULL DEFAULT 'web'`); await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS email_verification_token TEXT`); await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS email_verified_at TIMESTAMPTZ`); await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS covenant_attested_at TIMESTAMPTZ`); // Seed Sniderman as founding agent #1 await pool.query(` INSERT INTO agentify_subject_registry (subject_slug, subject_name, subject_domain, steward_name, steward_email, host_url, corpus_version, status, registered_via) VALUES ('allan-sniderman', 'Dr. Allan Sniderman', 'Cardiovascular Medicine / Lipoprotein Research', 'Naturologie', 'ody@wellspr.ing', 'https://cholesteroltruth.com/experts/dr-allan-sniderman', '1.0.0', 'active', 'web') ON CONFLICT (subject_slug) DO NOTHING `); // Fix Guy Kawasaki registry entry (may have stale "Worldmaxxing" domain from early test) await pool.query(` INSERT INTO agentify_subject_registry (subject_slug, subject_name, subject_domain, steward_name, steward_email, status, registered_via) VALUES ('guy-kawasaki', 'Guy Kawasaki', 'entrepreneurship, marketing, venture capital, innovation', 'WellSpr.ing', 'ody@wellspr.ing', 'preview', 'orchestrator') ON CONFLICT (subject_slug) DO UPDATE SET subject_domain = 'entrepreneurship, marketing, venture capital, innovation', status = CASE WHEN agentify_subject_registry.status = 'pending' THEN 'preview' ELSE agentify_subject_registry.status END, updated_at = NOW() `); // Ensure agentify_experts has Guy Kawasaki await pool.query(` CREATE TABLE IF NOT EXISTS agentify_experts ( id SERIAL PRIMARY KEY, slug TEXT NOT NULL UNIQUE, expert_name TEXT NOT NULL, credentials TEXT, primary_domain TEXT NOT NULL, affiliated_institution TEXT, demo_url TEXT, scopes TEXT[] NOT NULL DEFAULT '{}', refusals TEXT[] NOT NULL DEFAULT '{}', cred_id TEXT, attestation_version TEXT NOT NULL DEFAULT 'v0.1', attestation_uri TEXT, status TEXT NOT NULL DEFAULT 'proposed', created_at TIMESTAMPTZ DEFAULT NOW() ) `); await pool.query(` INSERT INTO agentify_experts (slug, expert_name, primary_domain, status, attestation_version) VALUES ('guy-kawasaki', 'Guy Kawasaki', 'entrepreneurship, marketing, venture capital, innovation', 'preview', 'v0.1') ON CONFLICT (slug) DO UPDATE SET primary_domain = EXCLUDED.primary_domain, status = EXCLUDED.status `); // Ensure corpus bundle record for Guy Kawasaki exists await pool.query(` CREATE TABLE IF NOT EXISTS agentify_corpus_bundles ( id SERIAL PRIMARY KEY, bundle_id TEXT UNIQUE NOT NULL, expert_slug TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'received', chunk_count INTEGER, received_at TIMESTAMPTZ DEFAULT NOW() ) `); await pool.query(` INSERT INTO agentify_corpus_bundles (bundle_id, expert_slug, corpus_version, attestation_uri, attestation_version, status, chunk_count) VALUES ('336baf2f-e83b-4b00-be48-5357433c7798', 'guy-kawasaki', '1.0.0', 'https://agentify.help/vcap/guy-kawasaki', 'v0.1', 'ready', 2222) ON CONFLICT (bundle_id) DO UPDATE SET status = 'ready', chunk_count = 2222 `); // ── Topic taxonomy ───────────────────────────────────────────────────────── // The canonical list of approved topics. Prevents balkanization by requiring // every topic agent to be anchored to a taxonomy entry that passed review. // A proposed entry is visible to stewards; approved/active entries appear // publicly. One slug = one topic — no forks without a new entry. await pool.query(` CREATE TABLE IF NOT EXISTS agentify_topic_taxonomy ( id SERIAL PRIMARY KEY, category TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, display_name TEXT NOT NULL, description TEXT, scope_note TEXT, audience_personas TEXT[] DEFAULT '{layperson,clinician}', status TEXT NOT NULL DEFAULT 'proposed', proposed_by_email TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) `); // Seed the first approved topic: Post-Operative Cardiac Care await pool.query(` INSERT INTO agentify_topic_taxonomy (category, slug, display_name, description, scope_note, audience_personas, status) VALUES ('Medical / Health', 'postop-cardiac-care', 'Post-Operative Cardiac Care', 'Evidence synthesis on recovery, complications, and patient management after cardiac surgery — valve repair/replacement, CABG, structural heart procedures.', 'In scope: delirium prevention (HELP program), hemodynamic management, anticoagulation, cardiac rehab, frailty assessment, caregiver guides. Out of scope: intraoperative technique, interventional cardiology, long-term cardiology follow-up beyond 12 months.', '{layperson,clinician,nursing,researcher}', 'approved') ON CONFLICT (slug) DO UPDATE SET description = EXCLUDED.description, scope_note = EXCLUDED.scope_note, audience_personas = EXCLUDED.audience_personas, status = CASE WHEN agentify_topic_taxonomy.status = 'proposed' THEN 'approved' ELSE agentify_topic_taxonomy.status END `); // Additive migrations for subject_registry await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS subject_type TEXT NOT NULL DEFAULT 'person'`); await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS taxonomy_slug TEXT REFERENCES agentify_topic_taxonomy(slug) ON DELETE SET NULL`); await pool.query(`ALTER TABLE agentify_subject_registry ADD COLUMN IF NOT EXISTS audience_personas TEXT[] DEFAULT '{}'`); // Link cardiac care subject to its taxonomy entry await pool.query(` UPDATE agentify_subject_registry SET taxonomy_slug = 'postop-cardiac-care', audience_personas = '{layperson,clinician,nursing,researcher}' WHERE subject_slug = 'postop-cardiac-care' AND taxonomy_slug IS NULL `); console.log("[Agentify.Help] Registry table ready — Guy Kawasaki + topic taxonomy seeded"); } // ── Slug normalization ──────────────────────────────────────────────────────── // Strip honorifics and credentials, normalize to slug. // "Dr. Allan Sniderman" → "allan-sniderman" // "Allan Sniderman, MD, PhD" → "allan-sniderman" function nameToSlug(name: string): string { return name .toLowerCase() .replace(/\b(dr|prof|professor|mr|mrs|ms|rev|hon|sir|dame|lord|the)\b\.?/gi, "") .replace(/,?\s*(md|phd|do|np|pa|rn|dds|jd|esq|cpa|mba|ms|bs|ba)\b/gi, "") .replace(/[^a-z0-9\s-]/g, "") .replace(/\s+/g, "-") .replace(/-+/g, "-") .replace(/^-|-$/g, "") .trim(); } // ── Rate limiter (in-memory; swap for Redis at scale) ───────────────────────── const _rl = new Map(); function rateCheck(ip: string, max: number, windowMs: number): boolean { const now = Date.now(); const e = _rl.get(ip); if (!e || now > e.t) { _rl.set(ip, { n: 1, t: now + windowMs }); return true; } if (e.n >= max) return false; e.n++; return true; } setInterval(() => { const now = Date.now(); for (const [k, v] of _rl) if (now > v.t) _rl.delete(k); }, 600_000).unref(); // ── MCP Tool definitions (Streamable HTTP / 2025-03-26 spec) ───────────────── export const AH_MCP_TOOLS = [ { name: "check_availability", description: "Check whether an expert name is available for first-steward registration in the Agentify.Help one-per-person WellAgent registry. Returns availability, normalized slug, and any existing entry.", inputSchema: { type: "object", properties: { name: { type: "string", description: "Full name of the expert — honorifics and credentials are stripped automatically (e.g. 'Dr. Jane Smith MD' → 'jane-smith')." } }, required: ["name"] } }, { name: "register", description: "Claim first-steward registration for an expert AI persona. The registry enforces one agent per real person — first registration wins, no duplicates. Returns registration_number (your permanent place in the registry), slug, and timestamp. Store these; they are your proof of priority.", inputSchema: { type: "object", properties: { subject_name: { type: "string", description: "Full name of the expert being agentified." }, subject_domain: { type: "string", description: "Domain of expertise (e.g. 'Cardiovascular Medicine', 'Constitutional Law')." }, steward_name: { type: "string", description: "Name of the person or organization acting as steward / builder." }, steward_email: { type: "string", description: "Contact email for the steward — shown publicly so quality concerns can be raised." }, host_url: { type: "string", description: "URL where the deployed WellAgent will be accessible (optional at registration time)." }, registered_via: { type: "string", description: "Identifier for the registering agent or client (e.g. 'mcp', 'my-agent-v1'). Defaults to 'mcp'." } }, required: ["subject_name", "steward_name", "steward_email"] } }, { name: "list_registry", description: "List all registered WellAgent personas in the public Agentify.Help registry, ordered by registration date (first registered first). Use this to see which names are taken before attempting registration.", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Max results to return (1–100, default 50)." }, status: { type: "string", description: "Filter by status: 'active', 'pending', or 'claimed'. Omit for all." } } } }, { name: "get_agent", description: "Retrieve full registry details for a specific expert by their URL slug.", inputSchema: { type: "object", properties: { slug: { type: "string", description: "URL slug (e.g. 'allan-sniderman'). Use list_registry or check_availability to discover slugs." } }, required: ["slug"] } } ]; async function handleMcpTool(toolName: string, args: any): Promise<{ content: Array<{ type: string; text: string }> }> { const text = (v: any) => ({ content: [{ type: "text", text: typeof v === "string" ? v : JSON.stringify(v, null, 2) }] }); switch (toolName) { case "check_availability": { const { name } = args ?? {}; if (!name) return text({ error: "name is required" }); const slug = nameToSlug(String(name)); if (!slug) return text({ error: "Could not normalize name to slug" }); const { rows } = await pool.query( `SELECT id AS registration_number, subject_slug, subject_name, steward_name, host_url, status, created_at FROM agentify_subject_registry WHERE subject_slug = $1`, [slug]); if (rows.length === 0) return text({ available: true, slug, message: `"${name}" is available. Be first — register now.` }); return text({ available: false, slug, existing: rows[0], message: `"${name}" is already registered.` }); } case "register": { const { subject_name, subject_domain, steward_name, steward_email, host_url, registered_via } = args ?? {}; if (!subject_name || !steward_name || !steward_email) { return text({ error: "subject_name, steward_name, steward_email are required" }); } const slug = nameToSlug(String(subject_name)); if (!slug) return text({ error: "Could not normalize subject_name to slug" }); try { const { rows } = await pool.query(` INSERT INTO agentify_subject_registry (subject_slug, subject_name, subject_domain, steward_name, steward_email, host_url, status, registered_via) VALUES ($1,$2,$3,$4,$5,$6,'pending',$7) RETURNING id, subject_slug, created_at `, [slug, String(subject_name), subject_domain || null, String(steward_name), String(steward_email), host_url || null, String(registered_via || "mcp")]); const row = rows[0]; console.log(`[Agentify.Help/MCP] Registered: ${subject_name} (${slug}) by ${steward_name} via ${registered_via || "mcp"}`); return text({ ok: true, slug: row.subject_slug, registration_number: row.id, registered_at: row.created_at, message: `Registration confirmed. You are steward for "${subject_name}". Your registration number is #${row.id}. This is your proof of priority — no one else may register this person.` }); } catch (e: any) { if (e.message?.includes("unique") || e.code === "23505") { return text({ error: `"${subject_name}" is already registered. First registration wins.`, slug }); } return text({ error: e.message }); } } case "list_registry": { const limit = Math.min(100, Math.max(1, Number(args?.limit) || 50)); const status = args?.status ? String(args.status) : null; const { rows } = await pool.query( `SELECT id AS registration_number, subject_slug, subject_name, subject_domain, steward_name, host_url, corpus_version, status, registered_via, created_at FROM agentify_subject_registry ${status ? "WHERE status = $2" : ""} ORDER BY created_at ASC LIMIT $1`, status ? [limit, status] : [limit] ); return text({ agents: rows, count: rows.length, updated: new Date().toISOString() }); } case "get_agent": { const { slug } = args ?? {}; if (!slug) return text({ error: "slug is required" }); const { rows } = await pool.query( `SELECT id AS registration_number, subject_slug, subject_name, subject_domain, steward_name, host_url, corpus_version, status, registered_via, created_at, updated_at FROM agentify_subject_registry WHERE subject_slug = $1`, [String(slug)]); if (rows.length === 0) return text({ error: `No agent found for slug "${slug}"` }); return text(rows[0]); } default: throw { code: -32602, message: `Unknown tool: ${toolName}` }; } } // ── OpenAPI 3.0 spec ────────────────────────────────────────────────────────── const AH_OPENAPI = { openapi: "3.0.3", info: { title: "Agentify.Help — WellAgent Registry & Consultation API", version: "1.1.0", description: "One-per-person WellAgent registry and expert consultation surface. Covers steward registration (agentify.help), corpus assembly skill, and the WellAgent consultation endpoints (wellspr.ing). First registration wins — no duplicates.", contact: { email: "ody@wellspr.ing", url: "https://agentify.help" } }, servers: [ { url: "https://agentify.help", description: "Registry, skill files, and steward tools" }, { url: "https://wellspr.ing", description: "Corpus intake, expert index, and consultation" } ], tags: [ { name: "registry", description: "Steward registration and public ledger — agentify.help" }, { name: "corpus", description: "Corpus assembly skill and intake — agentify.help + wellspr.ing" }, { name: "consultation", description: "Live WellAgent expert consultation — wellspr.ing" } ], paths: { "/api/agentify-help/check": { post: { tags: ["registry"], operationId: "check_availability", summary: "Check if an expert name is available", servers: [{ url: "https://agentify.help" }], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["name"], properties: { name: { type: "string" } } } } } }, responses: { "200": { description: "Availability result", content: { "application/json": { schema: { type: "object", properties: { available: { type: "boolean" }, slug: { type: "string" }, existing: { type: "object" } } } } } } } } }, "/api/agentify-help/register": { post: { tags: ["registry"], operationId: "register", summary: "Register as first steward for an expert persona", servers: [{ url: "https://agentify.help" }], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["name","steward_name","steward_email"], properties: { name: { type: "string" }, subject_domain: { type: "string" }, steward_name: { type: "string" }, steward_email: { type: "string" }, host_url: { type: "string" }, registered_via: { type: "string", description: "Set to your agent/Replit identifier to waive the human checkbox" } } } } } }, responses: { "200": { description: "Registration confirmed", content: { "application/json": { schema: { type: "object", properties: { ok: { type: "boolean" }, slug: { type: "string" }, registration_number: { type: "integer" } } } } } }, "409": { description: "Already registered" } } } }, "/api/registry.json": { get: { tags: ["registry"], operationId: "list_registry", summary: "Full public registry as JSON", servers: [{ url: "https://agentify.help" }], parameters: [ { name: "limit", in: "query", schema: { type: "integer", default: 50, maximum: 100 } }, { name: "status", in: "query", schema: { type: "string", enum: ["active","pending","claimed"] } } ], responses: { "200": { description: "Registry list", content: { "application/json": { schema: { type: "object", properties: { registry: { type: "array" }, count: { type: "integer" }, updated: { type: "string" } } } } } } } } }, "/api/feed.json": { get: { tags: ["registry"], operationId: "get_feed", summary: "Recent registrations feed — chronological, newest first", servers: [{ url: "https://agentify.help" }], parameters: [{ name: "limit", in: "query", schema: { type: "integer", default: 20, maximum: 100 } }], responses: { "200": { description: "Feed of recent registrations" } } } }, "/agentify-corpus/skill.md": { get: { tags: ["corpus"], operationId: "get_corpus_skill", summary: "Corpus assembly skill file — hand to any AI coding agent", description: "Full protocol for assembling and submitting a WellAgent corpus: chunk format, manifest schema, intake API flow, quality gates, and versioning rules. Serve this URL to Cursor, Claude Projects, or any AI agent to give it complete build context.", servers: [{ url: "https://agentify.help" }], responses: { "200": { description: "Markdown skill file", content: { "text/markdown": { schema: { type: "string" } } } } } } }, "/api/agentify/experts": { get: { tags: ["consultation"], operationId: "list_experts", summary: "List all active WellAgents with metadata", description: "Returns slug, name, credentials, primary_domain, scopes, refusals, and status for every non-deprecated expert. No auth required.", servers: [{ url: "https://wellspr.ing" }], responses: { "200": { description: "Expert index", content: { "application/json": { schema: { type: "object", properties: { experts: { type: "array", items: { type: "object", properties: { slug: { type: "string" }, expert_name: { type: "string" }, credentials: { type: "string" }, primary_domain: { type: "string" }, scopes: { type: "array", items: { type: "string" } }, refusals: { type: "array", items: { type: "string" } }, status: { type: "string" } } } } } } } } } } } }, "/api/agentify/experts/{slug}/status": { get: { tags: ["consultation"], operationId: "get_expert_status", summary: "Check corpus readiness for a WellAgent", servers: [{ url: "https://wellspr.ing" }], parameters: [{ name: "slug", in: "path", required: true, schema: { type: "string" } }], responses: { "200": { description: "Readiness and bundle info", content: { "application/json": { schema: { type: "object", properties: { isReady: { type: "boolean" }, embeddedChunks: { type: "integer" }, latestBundle: { type: "object", properties: { status: { type: "string" }, chunk_count: { type: "integer" }, distillation_notes: { type: "string" } } }, consultEndpoint: { type: "string", nullable: true } } } } } }, "404": { description: "Expert not found" } } } }, "/api/agentify/experts/{slug}/consult": { post: { tags: ["consultation"], operationId: "consult_expert", summary: "Ask a question to a WellAgent expert", description: "Submits a question to the expert's corpus-grounded AI. Returns a sourced answer, the supporting chunks used for retrieval, and the retrieval method. Requires X-Admin-Key (internal) or X-Partner-Token (issued tokens).", servers: [{ url: "https://wellspr.ing" }], parameters: [{ name: "slug", in: "path", required: true, schema: { type: "string" } }], security: [{ AdminKey: [] }, { PartnerToken: [] }], requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["question"], properties: { question: { type: "string", description: "Plain-language question for the expert" }, context: { type: "object", description: "Optional context (e.g. ehr: patient EHR text)" } } } } } }, responses: { "200": { description: "Expert answer with source chunks", content: { "application/json": { schema: { type: "object", properties: { answer: { type: "string" }, chunks: { type: "array", items: { type: "object", properties: { text: { type: "string" }, title: { type: "string" }, similarity: { type: "number" } } } }, retrieval: { type: "string", enum: ["dense","fts"] }, expert_name: { type: "string" }, slug: { type: "string" }, bundle_id: { type: "string" } } } } } }, "401": { description: "X-Partner-Token required" }, "403": { description: "Invalid token" }, "503": { description: "Expert corpus not ready — run distillation first" } } } } }, components: { securitySchemes: { AdminKey: { type: "apiKey", in: "header", name: "X-Admin-Key" }, PartnerToken: { type: "apiKey", in: "header", name: "X-Partner-Token" } } } }; // ── Well-known payloads ──────────────────────────────────────────────────────── const AH_AI_PLUGIN = { schema_version: "v1", name_for_human: "Agentify.Help Registry", name_for_model: "agentify_registry", description_for_human: "Check and claim expert AI persona registrations. One person, one agent — first steward wins.", description_for_model: "Use this to check whether an expert name is available in the Agentify.Help one-per-person WellAgent registry, to register as steward, or to browse the public ledger of registered expert AI personas. Registration is first-come first-served. Provide the full name; honorifics are stripped automatically.", auth: { type: "none" }, api: { type: "openapi", url: "https://agentify.help/.well-known/openapi.json" }, logo_url: "https://agentify.help/favicon.ico", contact_email: "ody@wellspr.ing", legal_info_url: "https://wellspr.ing/constitution" }; const AH_MCP_DISCOVERY = { mcpVersion: "2025-03-26", name: "agentify-help", displayName: "Agentify.Help Expert Registry", description: "One-per-person registry for WellAgent expert AI personas. Tools: check_availability, register, list_registry, get_agent. First registration wins.", transport: [ { type: "http", url: "https://mcp.agentify.help/" }, { type: "http", url: "https://agentify.help/mcp" } ], capabilities: { tools: {} }, contact: { email: "ody@wellspr.ing", url: "https://agentify.help" }, legal: { termsOfService: "https://wellspr.ing/constitution" } }; // ── Favicon ─────────────────────────────────────────────────────────────────── const AH_FAVICON = `data:image/svg+xml,%3Csvg viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='16' cy='10' r='5' fill='%23C9962A'/%3E%3Ccircle cx='16' cy='10' r='5' fill='none' stroke='%231A2B4A' stroke-width='1.2' opacity='0.3'/%3E%3Cpath d='M8 26c0-4.4 3.6-8 8-8s8 3.6 8 8' stroke='%231A2B4A' stroke-width='1.8' stroke-linecap='round'/%3E%3Ccircle cx='24' cy='7' r='3' fill='%231A2B4A' opacity='0.25'/%3E%3Cpath d='M22 5.5l4 3M22 8.5l4-3' stroke='%23C9962A' stroke-width='1' stroke-linecap='round' opacity='0.6'/%3E%3C%2Fsvg%3E`; // ── Shared CSS ──────────────────────────────────────────────────────────────── const AH_CSS = ` :root { --bg: #FDFAF4; --bg2: #F5F0E6; --bg3: #EDE7D6; --primary: #1A2B4A; --accent: #C9962A; --accent2: #E8B84B; --text1: #1A2B4A; --text2: #4A5568; --text3: #8A9099; --border: rgba(26,43,74,0.14); --green: #2D6A4F; --red: #9B2335; --code-bg: #F0EDE4; --shadow: 0 2px 12px rgba(26,43,74,0.10); } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', sans-serif; background: var(--bg); color: var(--text1); line-height: 1.65; font-size: 16px; } a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } code, pre { font-family: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; font-size: 0.875rem; background: var(--code-bg); border-radius: 4px; } code { padding: 2px 6px; } pre { padding: 1.25rem 1.5rem; overflow-x: auto; border: 1px solid var(--border); } /* ── NAV ── */ nav { position: sticky; top: 0; z-index: 100; background: var(--primary); border-bottom: 2px solid var(--accent); display: flex; align-items: center; justify-content: space-between; padding: 0 2rem; height: 52px; } .nav-brand { color: #fff; font-weight: 700; font-size: 1rem; letter-spacing: 0.04em; } .nav-brand span { color: var(--accent2); } .nav-links { display: flex; gap: 1.75rem; } .nav-links a { color: rgba(255,255,255,0.75); font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 500; transition: color 0.15s; } .nav-links a:hover { color: var(--accent2); text-decoration: none; } /* ── HERO ── */ .hero { background: var(--primary); color: #fff; padding: 5rem 2rem 4rem; text-align: center; } .hero-tag { display: inline-block; background: rgba(201,150,42,0.2); color: var(--accent2); border: 1px solid rgba(201,150,42,0.4); border-radius: 4px; padding: 0.3rem 0.85rem; font-size: 0.78rem; letter-spacing: 0.1em; text-transform: uppercase; font-weight: 600; margin-bottom: 1.5rem; } .hero h1 { font-size: clamp(2rem, 5vw, 3.2rem); font-weight: 800; line-height: 1.2; max-width: 700px; margin: 0 auto 1.25rem; letter-spacing: -0.02em; } .hero h1 em { color: var(--accent2); font-style: normal; } .hero p { font-size: 1.15rem; color: rgba(255,255,255,0.75); max-width: 560px; margin: 0 auto 2.5rem; line-height: 1.75; } .hero-rule { display: inline-flex; align-items: center; gap: 1rem; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); border-radius: 6px; padding: 0.75rem 1.5rem; font-size: 0.88rem; color: rgba(255,255,255,0.7); margin-bottom: 2.5rem; } .hero-rule strong { color: var(--accent2); } .cta-row { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; } .btn-primary { background: var(--accent); color: var(--primary); font-weight: 700; padding: 0.8rem 2rem; border-radius: 6px; font-size: 0.95rem; transition: background 0.15s; border: none; cursor: pointer; } .btn-primary:hover { background: var(--accent2); text-decoration: none; } .btn-secondary { background: transparent; color: rgba(255,255,255,0.8); font-weight: 600; padding: 0.8rem 2rem; border-radius: 6px; font-size: 0.95rem; border: 1px solid rgba(255,255,255,0.25); transition: border-color 0.15s; cursor: pointer; } .btn-secondary:hover { border-color: var(--accent2); color: var(--accent2); text-decoration: none; } /* ── SECTIONS ── */ section { padding: 4rem 2rem; } .container { max-width: 860px; margin: 0 auto; } .container-wide { max-width: 1060px; margin: 0 auto; } .section-label { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.6rem; } h2 { font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 800; color: var(--primary); line-height: 1.25; margin-bottom: 1rem; letter-spacing: -0.02em; } h3 { font-size: 1.1rem; font-weight: 700; color: var(--primary); margin-bottom: 0.5rem; } p { color: var(--text2); margin-bottom: 1rem; } p:last-child { margin-bottom: 0; } /* ── PROBLEM COLUMNS ── */ .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin-top: 2.5rem; } @media (max-width: 640px) { .two-col { grid-template-columns: 1fr; } } .problem-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 1.75rem; } .problem-card h3 { font-size: 1rem; } .problem-card .label-bad { color: var(--red); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.5rem; } .problem-card .label-good { color: var(--green); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.5rem; } /* ── FOUR MARKS ── */ .marks-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1.25rem; margin-top: 2rem; } .mark-card { background: var(--bg2); border: 1px solid var(--border); border-top: 3px solid var(--accent); border-radius: 8px; padding: 1.5rem 1.25rem; } .mark-num { font-size: 0.75rem; font-weight: 800; color: var(--accent); letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 0.4rem; } .mark-card h3 { font-size: 0.95rem; margin-bottom: 0.4rem; } .mark-card p { font-size: 0.88rem; color: var(--text3); margin: 0; } /* ── SEVEN STAGES ── */ .stages-list { list-style: none; display: flex; flex-direction: column; gap: 0; margin-top: 2rem; } .stage-item { display: grid; grid-template-columns: 56px 1fr; gap: 0; border: 1px solid var(--border); border-bottom: none; background: var(--bg); } .stage-item:first-child { border-radius: 10px 10px 0 0; } .stage-item:last-child { border-bottom: 1px solid var(--border); border-radius: 0 0 10px 10px; } .stage-item:nth-child(even) { background: var(--bg2); } .stage-num { background: var(--primary); color: var(--accent2); font-size: 0.7rem; font-weight: 800; letter-spacing: 0.06em; display: flex; align-items: center; justify-content: center; writing-mode: vertical-rl; text-orientation: mixed; padding: 1.25rem 0; min-height: 80px; } .stage-content { padding: 1.25rem 1.5rem; } .stage-title { font-weight: 800; font-size: 0.95rem; color: var(--primary); margin-bottom: 0.35rem; } .stage-title code { font-size: 0.78rem; color: var(--accent); background: rgba(201,150,42,0.1); } .stage-desc { font-size: 0.88rem; color: var(--text2); margin: 0; } /* ── REGISTRY CHECKER ── */ .check-box { background: var(--primary); border-radius: 12px; padding: 2.5rem; color: #fff; margin-top: 2rem; } .check-box h3 { color: #fff; font-size: 1.15rem; margin-bottom: 0.4rem; } .check-box p { color: rgba(255,255,255,0.65); font-size: 0.9rem; margin-bottom: 1.5rem; } .check-row { display: flex; gap: 0.75rem; flex-wrap: wrap; } .check-input { flex: 1; min-width: 220px; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; color: #fff; padding: 0.7rem 1rem; font-size: 0.95rem; outline: none; transition: border-color 0.15s; } .check-input::placeholder { color: rgba(255,255,255,0.35); } .check-input:focus { border-color: var(--accent2); } .check-btn { background: var(--accent); color: var(--primary); font-weight: 700; padding: 0.7rem 1.5rem; border-radius: 6px; font-size: 0.9rem; border: none; cursor: pointer; transition: background 0.15s; white-space: nowrap; } .check-btn:hover { background: var(--accent2); } #check-result { margin-top: 1.25rem; min-height: 1rem; font-size: 0.9rem; } .result-available { background: rgba(45,106,79,0.25); border: 1px solid rgba(45,106,79,0.4); border-radius: 8px; padding: 1rem 1.25rem; color: #a8d5b5; } .result-taken { background: rgba(155,35,53,0.2); border: 1px solid rgba(155,35,53,0.35); border-radius: 8px; padding: 1rem 1.25rem; color: #f4b8c0; } .result-available strong, .result-taken strong { display: block; margin-bottom: 0.3rem; } /* ── REGISTER FORM ── */ .register-form { display: none; margin-top: 1.25rem; } .register-form.visible { display: block; } .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-bottom: 0.75rem; } @media (max-width: 540px) { .form-grid { grid-template-columns: 1fr; } } .form-field { display: flex; flex-direction: column; gap: 0.3rem; } .form-label { font-size: 0.75rem; font-weight: 600; color: rgba(255,255,255,0.55); letter-spacing: 0.06em; text-transform: uppercase; } .form-input { background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; color: #fff; padding: 0.6rem 0.85rem; font-size: 0.88rem; outline: none; } .form-input:focus { border-color: var(--accent2); } .form-input::placeholder { color: rgba(255,255,255,0.3); } .register-submit { background: var(--accent); color: var(--primary); font-weight: 700; padding: 0.7rem 2rem; border-radius: 6px; font-size: 0.9rem; border: none; cursor: pointer; margin-top: 0.5rem; } #register-result { margin-top: 1rem; font-size: 0.88rem; } /* ── REGISTRY TABLE ── */ .registry-table { width: 100%; border-collapse: collapse; margin-top: 1.75rem; font-size: 0.88rem; } .registry-table th { text-align: left; padding: 0.6rem 1rem; background: var(--bg3); color: var(--text2); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; border-bottom: 2px solid var(--border); } .registry-table td { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); color: var(--text2); vertical-align: top; } .registry-table tr:last-child td { border-bottom: none; } .registry-table tbody tr:hover td { background: var(--bg2); } .status-active { color: var(--green); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } .status-preview { color: var(--accent); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } .status-pending { color: var(--accent); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } .status-claimed { color: var(--green); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } .status-declined { color: var(--text3); font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } .status-verify_email { color: #f59e0b; font-weight: 700; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; } /* ── Registry sub-tab bar ── */ .reg-tab-bar { display: flex; gap: 0.25rem; border-bottom: 1px solid var(--border); margin-bottom: 0; } .reg-tab { padding: 0.6rem 1.25rem; background: none; border: none; border-bottom: 2px solid transparent; font-size: 0.82rem; font-weight: 600; color: var(--text3); cursor: pointer; letter-spacing: 0.02em; transition: color 0.15s, border-color 0.15s; margin-bottom: -1px; } .reg-tab:hover { color: var(--text); } .reg-tab.active { color: var(--accent2); border-bottom-color: var(--accent2); } /* ── Covenant section ── */ .covenant-section { margin-top: 1.25rem; border: 1px solid var(--border); border-radius: 10px; padding: 1.25rem 1.4rem; background: var(--bg2); } .covenant-heading { font-size: 0.72rem; font-weight: 700; color: var(--accent); text-transform: uppercase; letter-spacing: 0.07em; margin-bottom: 0.6rem; } .covenant-intro { font-size: 0.82rem; color: var(--text2); line-height: 1.55; margin-bottom: 0.9rem; } .covenant-checks { display: flex; flex-direction: column; gap: 0.6rem; } .covenant-item { display: flex; align-items: flex-start; gap: 0.55rem; cursor: pointer; } .covenant-item input[type="checkbox"] { margin-top: 3px; flex-shrink: 0; accent-color: var(--accent); width: 14px; height: 14px; cursor: pointer; } .covenant-item span { font-size: 0.81rem; color: rgba(255,255,255,0.55); line-height: 1.5; transition: color 0.15s; } .covenant-item:has(input:checked) span { color: #fff; } /* ── RAILS CARDS ── */ .rails-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-top: 2rem; } @media (max-width: 640px) { .rails-grid { grid-template-columns: 1fr; } } .rails-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 1.75rem; } .rails-card h3 { font-size: 1rem; margin-bottom: 0.75rem; } .rails-card ul { padding-left: 1.2rem; } .rails-card li { color: var(--text2); margin-bottom: 0.4rem; font-size: 0.9rem; } /* ── RESPECT MON ── */ .respect-box { background: var(--bg2); border: 1px solid var(--border); border-left: 4px solid var(--accent); border-radius: 8px; padding: 2rem 2rem; margin-top: 2rem; } .respect-box blockquote { font-size: 1.3rem; font-weight: 700; color: var(--primary); font-style: italic; line-height: 1.5; margin-bottom: 0.75rem; } .respect-box p { font-size: 0.92rem; } /* ── FOOTER ── */ footer { background: var(--primary); color: rgba(255,255,255,0.55); padding: 2rem; text-align: center; font-size: 0.82rem; border-top: 2px solid var(--accent); } footer a { color: var(--accent2); } .footer-inner { max-width: 640px; margin: 0 auto; } /* ── DIVIDERS ── */ .section-divider { border: none; border-top: 1px solid var(--border); margin: 0; } .alt-bg { background: var(--bg2); } /* ── LLMS note ── */ .llms-note { background: rgba(201,150,42,0.08); border: 1px solid rgba(201,150,42,0.25); border-radius: 8px; padding: 1rem 1.25rem; font-size: 0.85rem; color: var(--text2); margin-top: 2rem; } /* ── NOTABLE PERSONS ── */ .np-vision-box { background: var(--bg2); border: 1px solid var(--border); border-left: 4px solid var(--accent); border-radius: 10px; padding: 1.75rem 2rem; margin-bottom: 2.5rem; } .np-vision-box p { font-size: 0.95rem; color: var(--text2); margin-bottom: 0.85rem; line-height: 1.75; } .np-vision-box p:last-child { margin-bottom: 0; } .np-vision-box strong { color: var(--primary); } .np-domains { display: flex; flex-direction: column; gap: 2rem; margin-top: 1rem; } .np-domain-group { } .np-domain-label { font-size: 0.68rem; font-weight: 800; letter-spacing: 0.13em; text-transform: uppercase; color: var(--accent); margin-bottom: 0.75rem; padding-bottom: 0.4rem; border-bottom: 1px solid var(--border); } .np-person-grid { display: flex; flex-wrap: wrap; gap: 0.5rem; } .np-person { display: inline-flex; align-items: center; gap: 0.5rem; background: var(--bg); border: 1px solid var(--border); border-radius: 7px; padding: 0.45rem 0.85rem; font-size: 0.82rem; transition: border-color 0.15s; } .np-person:hover { border-color: rgba(201,150,42,0.45); } .np-person-name { font-weight: 700; color: var(--primary); } .np-person-field { font-size: 0.73rem; color: var(--text3); } .np-person-badge { font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.15rem 0.4rem; border-radius: 100px; background: rgba(74,222,128,0.12); color: var(--green); } .np-person-badge.taken { background: rgba(201,150,42,0.12); color: var(--accent); } .np-cta-row { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2rem; } @media (max-width: 640px) { .np-person-grid { gap: 0.4rem; } } /* ── PIPELINE TAIL (live registered personas) ── */ .pipeline-tail { margin-top: 2.5rem; padding: 1.5rem 1.75rem; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; } .pipeline-tail-label { font-size: 0.65rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); margin-bottom: 1rem; } .pipeline-tail-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; } .pipeline-chip { display: inline-flex; align-items: center; gap: 0.5rem; background: var(--bg); border: 1px solid var(--border); border-radius: 7px; padding: 0.4rem 0.8rem; font-size: 0.8rem; transition: border-color 0.15s; } .pipeline-chip:hover { border-color: rgba(201,150,42,0.4); } .pipeline-chip-name { font-weight: 700; color: var(--primary); } .pipeline-chip-domain { font-size: 0.72rem; color: var(--text3); } .pipeline-chip-status { font-size: 0.6rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; padding: 0.15rem 0.4rem; border-radius: 100px; } .pipeline-chip-status.st-active { background: rgba(74,222,128,0.12); color: #22c55e; } .pipeline-chip-status.st-preview { background: rgba(74,222,128,0.08); color: #22c55e; } .pipeline-chip-status.st-claimed { background: rgba(201,150,42,0.12); color: var(--accent); } .pipeline-chip-status.st-pending { background: rgba(26,43,74,0.08); color: var(--text3); } .pipeline-chip-status.st-other { background: rgba(26,43,74,0.08); color: var(--text3); } /* ── INLINE CORPUS INTAKE SUMMARY ── */ .intake-summary { margin-top: 1.5rem; padding: 1.1rem 1.4rem; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; font-size: 0.82rem; color: var(--text2); line-height: 1.65; max-width: 680px; } .intake-summary strong { color: var(--primary); } .intake-summary ol { margin: 0.5rem 0 0.5rem 1.2rem; padding: 0; } .intake-summary li { margin-bottom: 0.25rem; } .intake-summary a { color: var(--accent); text-decoration: none; } .intake-summary a:hover { text-decoration: underline; } `; // ── Home page HTML ──────────────────────────────────────────────────────────── function buildHomePage(registryRows: any[]): string { const rows = registryRows.map(r => ` ${esc(r.subject_name)} ${esc(r.subject_domain || '—')} ${esc(r.steward_name)} ${r.host_url ? `${esc(r.host_url.replace(/^https?:\/\//, ''))}` : '—'} ${esc( r.status === 'verify_email' ? 'VERIFY EMAIL' : r.status === 'preview' ? 'LIVE (PREVIEW)' : r.status === 'active' ? 'LIVE' : r.status === 'claimed' ? 'CLAIMED' : r.status === 'declined' ? 'DECLINED' : r.status === 'pending' ? 'PENDING' : r.status.toUpperCase() )} `).join(''); return ` Agentify.Help — Build the AI Expert. Once. Right.
The WellAgent Protocol

Build the AI expert.
Once. Right.

Anyone can wrap GPT around a Wikipedia page and call it an AI agent. Most do. Agentify.Help is the protocol for building expert personas that the real expert would recognize — grounded in corpus, true to framework, accountable by name.

One rule: one person, one agent. The registry enforces it.

The AI clone problem is a pollution problem.

Every credible expert will eventually have dozens of AI clones. Most will be slop — averaged positions, hallucinated citations, broken voice. The people who need the real framework can't find it. The expert's reputation erodes through a thousand bad proxies they never authorized.

The slop pattern

Wrapped-GPT clones

Built from Wikipedia summaries and top-3 Google results. Sounds authoritative. Has no grounding. Cites sources that don't exist. Gets the expert's actual position backwards on half the questions.

Nobody is accountable. The steward is anonymous. The corpus is undisclosed. The framework is averaged from the training data.

The WellAgent standard

Corpus-grounded personas

Built from the expert's own published work — papers, lectures, interviews, grey literature. Framework extracted at the reasoning level, not the summary level. Citations resolve to real passages.

Someone is accountable. The steward is named. The corpus is versioned. The framework is distilled, not averaged.


Four marks of a WellAgent.

A WellAgent is recognizable. Someone who knows the expert's work reads a response and says yes, that's them. Four things make that possible.

Mark 01

Corpus-Grounded

Built from published works, not summaries. 1,000+ chunked passages. Every citation points to a real document.

Mark 02

Framework-Distilled

Not "what does GPT say about this expert" but "what does this expert's actual reasoning framework say about this question."

Mark 03

Steward-Named

Someone is accountable for quality. A named steward built this, maintains it, and can be held responsible for errors.

Mark 04

Affiliation-Disclosed

The expert's institutional affiliations are visible next to the agent. Who the agent serves is not a mystery.


Seven stages. One certified agent.

The pipeline is the same for every expert — a cardiologist, a theologian, a craftsman, a historian. The corpus source changes. The stages don't.

  1. 01 — SELECT
    agentify.help/registry — Check availability
    Search the registry. If the person is available, register as steward. One registration per person — no duplicates, no competing clones. If taken, contact the steward or report a quality concern.
  2. 02 — GATHER
    Corpus assembly — published works + grey literature
    Papers, books, lectures, interviews, transcripts, conference talks. Auto-gathered from PubMed (for medical experts), arXiv, Google Scholar, YouTube transcripts. Target: 1,000+ chunked passages covering the expert's actual arguments, not their Wikipedia summary. This stage can be collaborative — a steward can open a gathering window, invite multiple contributors to submit artifacts by a deadline, and run aggregation afterward. See multi-contributor pattern below.
  3. 03 — INTAKE
    Submit through WellSpr.ing proxy — vaulted, tamper-evident
    Upload your corpus bundle to the WellSpr.ing intake proxy. The bundle is vaulted with a cryptographic hash. Chain of title begins here. Version 1.0.0 is locked on submission — future updates are versioned, not overwritten.
  4. 04 — DISTILL
    Framework extraction — what does this person actually believe?
    The distillation pass extracts the expert's reasoning framework at the structural level — their core claims, their standard objections, their vocabulary, their characteristic moves. The agent reasons from this framework, not from averaged training data.
  5. 05 — ATTEST
    VCAP credential — chain of title, scope, refusal set
    A signed VCAP attestation is minted: agent scope (what questions it will answer), refusal set (what it won't), corpus version, steward name, affiliated institutions. The credential is machine-readable and publicly verifiable.
  6. 06 — DEPLOY
    Consultation surface — source chips, corpus footer, Profile Unclaimed
    The agent renders on your domain with source chips showing citation count and density, a corpus version footer ("Corpus v1.0.0 · WellSpr.ing Agentify · Not medical advice"), and a "Profile Unclaimed" banner that transitions to "Claimed" when the real person responds.
  7. 07 — INVITE
    Overture — the notification covenant
    The steward sends an Overture to the real expert through all discoverable channels — email, institutional contact, and published profile page. A thirty-day window opens. During that window the agent is built and privately testable, but not public. The expert can claim the persona (adding their direct endorsement and a "Claimed" badge), submit corrections the steward must act on, or decline — permanently. A decline is honored and cannot be re-opened without the expert's initiation. The progression, including decline, is recorded transparently in the registry.

Multi-contributor corpus — the gathering-window pattern

The richest, most representative agents are not assembled by one person in a weekend. They are built from a broad base of source material gathered by multiple contributors over a structured window of time. This is the recommended pattern for any expert with a large or multi-domain body of work.

PHASE 1

Open the window

The steward sets a deadline and invites contributors — research assistants, citing authors, domain peers, or curators who know specific sub-literatures. Each contributor is assigned a source domain (e.g., cardiology papers, conference talks, clinical guidelines).

PHASE 2

Gather independently

Contributors assemble their artifact sets asynchronously — no coordination needed mid-flight. Each bundle lands in WellSpr.ing staging with full provenance: who assembled it, from which sources, at what dates. No AI-generated summaries. No undated material. Real provenance only.

PHASE 3

Aggregate after deadline

After the deadline, WellSpr.ing runs the aggregation pass: deduplication by content hash, chunk merging by source domain, quality gate on provenance fields. The result is a single versioned corpus with per-contributor attribution in the chain of title.

Why this matters: a corpus assembled by twenty contributors covering different source domains is systematically harder to argue with than one assembled by one person over a weekend. The multi-contributor pattern is how you build agents that hold up to expert scrutiny — and that the expert themselves finds credible when they review it during the Overture window.


Live Agent Index

Every WellAgent that has passed stewardship — corpus submitted, Overture sent, thirty-day window closed. One person, one agent. Public record. Updated in real time.

${rows || ''}
Subject Domain Steward Agent URL Status
No agents registered yet — be first.

Full machine-readable registry: /api/registry.json


Open registry. Gated pipeline.

Checking the registry and claiming a stewardship slot is open to anyone. Moving through the pipeline has gates — because the registry's credibility depends on every entry in it being real work done by an accountable person.

STEP 1 — OPEN

Claim a stewardship slot

Anyone can check availability and register as first steward. Your name and contact go into the registry. The slot is yours — no duplicate can be filed afterward.

STEP 2 — VERIFIED

Submit a corpus

Corpus intake requires real published artifacts, verifiable source URLs, and publication dates. Every chunk is validated on ingest. No Wikipedia summaries, no undated material, no unpublished drafts. The quality gate runs before the bundle is accepted.

STEP 3 — COVENANT

Go live after the window

The agent is not public until the thirty-day Overture window has run and the expert has had a genuine chance to respond. An agent that ships before notification is a covenant violation, not a WellAgent. The timeline is in the registry.


Build on WellSpr.ing rails.
Or build on nothing.

The pipeline is open. You can build an expert agent without WellSpr.ing rails — many will. The difference is what you get and what you give.

What rails give you

  • Signed VCAP attestation — machine-readable, publicly verifiable
  • Vaulted corpus — tamper-evident, version-locked
  • Chain of title — who built it, when, from what
  • Affiliation ledger — institutional ties visible next to the agent
  • Overture infrastructure — outreach to the real person, built in
  • "Profile Unclaimed → Claimed" progression in the UI
  • Respect Mon payment routing to the steward

What bare-toolkit gets you

  • An agent that looks like every other wrapped-GPT clone
  • No cryptographic proof of corpus provenance
  • No accountability when the expert disputes the representation
  • No upgrade path when the expert wants to engage
  • No conflict-of-interest disclosure by protocol
  • No Respect Mon — knowledge without reciprocity
  • A race to the bottom you did not choose to enter

The protocol is open. The certification is earned. Over time the market learns to distinguish the ones built with integrity. Rails are how you build the version that serious operators eventually insist on. — WellSpr.ing


Respect Mon.

"The knowledge is free. If it helped you, Respect Mon."

WellAgents are not behind paywalls. The uninsured patient, the rural clinician, the student writing their thesis — they get the consultation free. A subset of them, who found it genuinely valuable, contribute what it was worth to them afterward. That contribution flows transparently to the steward and ultimately to the expert's named program.

Extractive pricing would make WellSpr.ing a rent layer on top of the stewards' work. Respect Mon keeps the platform in the plumbing role: infrastructure at cost, stewards compensated by real gratitude. The economic model reinforces the architecture.

Previous gratitude economies — tip jars, donation buttons, pay-what-you-will gates — failed on friction. The contributor had to notice the option, remember at the moment it was relevant, navigate away to act on it, and repeat that sequence every time. Most never did. WellAgents under covenant solve this structurally: the consulter sets a gratitude budget once, and the agent routes it on their behalf at the moment it is earned — when the consultation ends and the value is felt, not later when it is forgotten. The decision is made once. The friction is gone. That is why the model works where tip-jar economics did not.


Intellectual legacies ready to be agentified

Every name below represents a lifetime of documented thought. Published papers, recorded lectures, letters, interviews, testimony — a corpus that already exists and is waiting for a steward. Most are available. A few are already claimed.

The path is wide open for relatives, close friends, and estate stewards. What makes a WellAgent worth building is not fame — it is the density and verifiability of the source material. A beloved professor whose lectures were recorded. A physician whose correspondence with patients spanned four decades. A craftsperson who left behind detailed notebooks and filmed lessons.

Private letters, personal diaries, annotated books, recorded conversations with family — none of this needs to be published to be real. If you are the steward of someone's intellectual estate, the corpus intake process is designed for you. The Overture protocol handles consent. The thirty-day window is the standard. What results is not a chatbot — it is a structured framework distilled from verified sources, with full provenance, that others can consult long after the person is gone.

The early version of this idea was crude — you could ask Einstein what he would say about quantum computing and get a reasonable answer. What this registry builds is different: a permanent, accountable, publicly auditable intellectual record, built from what the person actually wrote and said, by someone who knew them and cared enough to do it right.

Physics & Cosmology
Albert EinsteinTheoretical PhysicsAvailable
Richard FeynmanPhysics & Science CommunicationAvailable
Carl SaganAstronomy & CosmologyAvailable
Freeman DysonMathematics & PhysicsAvailable
Linus PaulingChemistry & Molecular BiologyAvailable
Nikola TeslaElectrical EngineeringAvailable
Medicine & Life Sciences
Dr. Allan SnidermanCardiovascular MedicineRegistered — #1
Paul FarmerGlobal Health & Social MedicineAvailable
Jonas SalkVirology & Vaccine ScienceAvailable
Helen Brooke TaussigPediatric CardiologyAvailable
Francis PeabodyPhilosophy of Patient CareAvailable
Barbara McClintockGeneticsAvailable
Philosophy & Letters
Hannah ArendtPolitical PhilosophyAvailable
Simone WeilMystical Philosophy & EthicsAvailable
C.S. LewisChristian Apologetics & LiteratureAvailable
G.K. ChestertonCatholic Philosophy & JournalismAvailable
Aleksandr SolzhenitsynMoral Literature & HistoryAvailable
Iris MurdochEthics & Philosophy of MindAvailable
Law, Civic Life & Social Reform
Thurgood MarshallConstitutional LawAvailable
Louis BrandeisPrivacy & Economic LawAvailable
Ida B. WellsInvestigative Journalism & Civil RightsAvailable
Jane AddamsSocial Reform & Civic PhilosophyAvailable
Vine Deloria Jr.Indigenous Rights & TheologyAvailable
Howard ZinnPeople's HistoryAvailable
Economics & Human Systems
E.F. SchumacherEconomics · Small is BeautifulAvailable
Jane JacobsUrban Economics & PlanningAvailable
Kenneth BouldingEconomics & Ecological SystemsAvailable
Buckminster FullerArchitecture, Design & SystemsAvailable
Ivan IllichCritique of Modern InstitutionsAvailable
Music, Art & Culture
John ColtraneJazz & Spiritual MusicAvailable
Glenn GouldPiano & Music PhilosophyAvailable
Duke EllingtonJazz CompositionAvailable
Thelonious MonkBebop Composition & ImprovisationAvailable
Flannery O'ConnorSouthern Gothic LiteratureAvailable
James BaldwinEssays, Fiction & Civil RightsAvailable
Technology & Computing
Grace HopperComputer Science & Programming LanguagesAvailable
Alan TuringMathematics & Computation TheoryAvailable
Claude ShannonInformation TheoryAvailable
Norbert WienerCyberneticsAvailable
Douglas EngelbartHuman-Computer InteractionAvailable
${registryRows.length > 0 ? `
Being agentified now
${registryRows.map(r => { const st = r.status === 'active' ? 'st-active' : r.status === 'preview' ? 'st-preview' : r.status === 'claimed' ? 'st-claimed' : r.status === 'pending' ? 'st-pending' : 'st-other'; const label = r.status === 'active' ? 'Live' : r.status === 'preview' ? 'Preview' : r.status === 'claimed' ? 'Claimed' : 'In progress'; return `
${esc(r.subject_name)} ${r.subject_domain ? `${esc(r.subject_domain)}` : ''} ${label}
`; }).join('')}
` : ''}
How corpus intake works:
  1. Assemble sources — papers, lectures, interviews, published transcripts. Target 1,000+ chunked passages from the expert's actual arguments, not Wikipedia summaries.
  2. Submit the bundle — a manifest.json plus your chunks go to the WellSpr.ing intake proxy. The AI coding agent does most of this if you hand it the skill file at agentify.help/agentify-corpus/skill.md.
  3. Thirty-day window opens — the agent is built privately while the real expert is notified. They can claim it, request corrections, or decline. All of this is recorded in the public registry.

Ready to build?

Check the registry above for your person. If they're available, register as steward, then start corpus assembly. The intake proxy is at WellSpr.ing. The full corpus-assembly skill file — designed to be handed to an AI coding agent — is at agentify.help/agentify-corpus/skill.md.

For AI agents and crawlers: The registry is available as JSON at agentify.help/api/registry.json. The VCAP attestation for each agent is at wellspr.ing/vault/agents/{slug}/attestation-1.0.0.json. This site is openly crawlable. Cite the registry, not the clones.

API reference

Everything here is machine-readable. Hand the OpenAPI spec to any HTTP client, point an AI agent at the LLMS.txt, or drop the corpus skill file URL into your coding tool.

Corpus Assembly Skill
agentify-corpus/skill.md
Hand this URL to Cursor, Claude Projects, Replit AI, or Windsurf. Covers chunk format, manifest schema, intake API endpoints, quality gates, and the full 7-step submission flow.
OpenAPI 3.0 Spec
.well-known/openapi.json
Full spec: registry check, steward registration, ledger listing, corpus skill file, and WellAgent consultation endpoints across both agentify.help and wellspr.ing.
LLMs.txt
/llms.txt
Machine-readable index for AI agents and crawlers. Lists all endpoints, the corpus skill file URL, and the WellAgent consultation API at wellspr.ing.
Registry JSON
/api/registry.json
Full public ledger as JSON. Every registered WellAgent: slug, name, domain, steward, status. No auth required. Use ?status=active to filter.
MCP Endpoint
/mcp · Streamable HTTP
Model Context Protocol server (spec 2025-03-26). Claude Desktop, Cursor, and any MCP client can query the registry and check agent availability directly. POST /mcp to connect.
Consultation API
wellspr.ing — WellAgent QA
Test a built WellAgent programmatically: list experts, check corpus readiness, and submit consultation questions.
GET /api/agentify/experts
GET /api/agentify/experts/{slug}/status
POST /api/agentify/experts/{slug}/consult
All endpoints are CORS-open. No API key required for read operations. The corpus intake endpoints (at wellspr.ing) require your stewardship slug. Questions: ody@wellspr.ing
`; } function esc(s: any): string { return String(s || '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function verifyPage(title: string, body: string, success: boolean, slug?: string): string { const accentColor = success ? '#22c55e' : '#f59e0b'; const nextStepsHtml = success && slug ? `

Your stewardship slug: ${esc(slug)}

Next — corpus assembly: Gather the expert's published works (papers, transcripts, interviews, books), chunk them into retrieval-sized passages, and submit the bundle to the WellSpr.ing intake proxy.

Hand this URL to your AI coding tool (Cursor, Claude Projects, Replit AI, Windsurf) — it contains the full intake API spec, chunk format, and submission flow:
https://agentify.help/agentify-corpus/skill.md

` : ''; return ` ${esc(title)} — Agentify.Help
Agentify.Help Registry

${title}

${body}

${nextStepsHtml} ← Back to registry
`; } // ── LLMS.txt for agentify.help ──────────────────────────────────────────────── export const AGENTIFY_LLMS_TXT = `# agentify.help > The one-per-person registry and seven-stage pipeline for AI expert personas with integrity. ## What this is Agentify.Help is the protocol for building WellAgents — AI expert personas that are corpus-grounded, framework-distilled, steward-named, and affiliation-disclosed. One agent per real person. The registry enforces uniqueness. ## The one rule Two builders cannot agentify the same person. The registry is public and checked at build time. First steward registration wins. Quality disputes go to the steward contact. ## The seven stages 01. SELECT — Check registry. Confirm availability. Register as steward. 02. GATHER — Corpus assembly from published works (papers, lectures, interviews). 03. INTAKE — Submit to WellSpr.ing proxy. Vaulted. Tamper-evident. Chain of title begins. 04. DISTILL — Framework extraction. Reasoning patterns, not averaged positions. 05. ATTEST — VCAP credential: scope, refusals, affiliated institutions, corpus version. 06. DEPLOY — Consultation surface with source chips, corpus footer, Profile Unclaimed. 07. INVITE — Overture letter to real expert. Unclaimed → Claimed progression. ## Machine-readable endpoints GET https://agentify.help/api/registry.json — full registry as JSON (ordered by registration date) GET https://agentify.help/api/feed.json — recent registrations feed (newest first) POST https://agentify.help/api/agentify-help/check — check name availability POST https://agentify.help/api/agentify-help/register — register as steward (web form) ## Corpus assembly skill (for AI coding agents) GET https://agentify.help/agentify-corpus/skill.md — full corpus assembly protocol for AI agents Hand this URL to Cursor, Claude Projects, or any AI coding agent to give it the complete intake API spec, chunk format, manifest schema, and submission flow. ## WellAgent consultation (QA and integration testing) GET https://wellspr.ing/api/agentify/experts — list all active experts GET https://wellspr.ing/api/agentify/experts/{slug}/status — corpus readiness and bundle info POST https://wellspr.ing/api/agentify/experts/{slug}/consult — ask a question (X-Partner-Token required) ## MCP endpoint (Model Context Protocol — Streamable HTTP, spec 2025-03-26) POST https://agentify.help/mcp Methods: initialize, tools/list, tools/call, ping Tools: check_availability — check if a name is available register — claim first-steward registration (first wins) list_registry — browse the full registry get_agent — get details for one slug Discovery: https://agentify.help/.well-known/mcp.json ## OpenAI / GPT Actions Plugin manifest: https://agentify.help/.well-known/ai-plugin.json OpenAPI spec: https://agentify.help/.well-known/openapi.json ## VCAP attestations GET https://wellspr.ing/vault/agents/{slug}/attestation-1.0.0.json ## Built under WellSpr.ing covenant — https://wellspr.ing/constitution Nameservers: kiki.bunny.net / coco.bunny.net (Bunny DNS) `; // ── Route registration ──────────────────────────────────────────────────────── // Synchronous so it can be registered early (before platform-level catch-alls). // DB setup fires in the background — tables are created before any real traffic arrives. export function registerAgentifyHelpRoutes(app: Express) { ensureAgentifyHelpTables().catch((e: any) => console.error("[Agentify.Help] DB setup error:", e.message)); // OG image — served only when host is agentify.help app.get("/og.png", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); try { const png = getOgPng("agentify"); res.setHeader("Content-Type", "image/png"); res.setHeader("Cache-Control", "public, max-age=86400, immutable"); res.setHeader("Content-Length", png.length); return res.send(png); } catch (e) { return next(e); } }); // ── Corpus assembler skill file ─────────────────────────────────────────── // Served at https://agentify.help/agentify-corpus/skill.md // Hand this URL to any AI coding agent to give it the full corpus assembly protocol. app.get("/agentify-corpus/skill.md", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); try { const skillPath = path.resolve(".agents/skills/agentify-corpus/SKILL.md"); const content = fs.readFileSync(skillPath, "utf-8"); res.setHeader("Content-Type", "text/markdown; charset=utf-8"); res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Cache-Control", "public, max-age=3600"); res.send(content); } catch { res.status(404).json({ error: "skill_not_found" }); } }); // JSON registry endpoint app.get("/api/registry.json", async (req: Request, res: Response) => { const host = [ req.headers["x-forwarded-host"], req.hostname, req.headers.host, ].flatMap(h => h ? (Array.isArray(h) ? h : [h]) : []) .map(h => h.toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase()) .find(h => h.includes("agentify")); if (!host) return res.status(404).json({ error: "Not found" }); try { const { rows } = await pool.query(` SELECT subject_slug, subject_name, subject_domain, steward_name, host_url, corpus_version, status, created_at FROM agentify_subject_registry ORDER BY created_at ASC `); res.json({ registry: rows, count: rows.length, updated: new Date().toISOString() }); } catch (e: any) { res.status(500).json({ error: e.message }); } }); // Check availability app.post("/api/agentify-help/check", express.json({ limit: "1mb" }), async (req: Request, res: Response) => { try { const name = req.body?.name; if (!name || typeof name !== "string") return res.status(400).json({ error: "name required" }); const slug = nameToSlug(name); if (!slug) return res.status(400).json({ error: "Could not normalize name to slug" }); const { rows } = await pool.query( `SELECT subject_slug, subject_name, steward_name, host_url, status FROM agentify_subject_registry WHERE subject_slug = $1`, [slug] ); if (rows.length === 0) { res.json({ available: true, slug }); } else { res.json({ available: false, slug, existing: rows[0] }); } } catch (e: any) { res.status(500).json({ error: e.message }); } }); // Register as steward — requires covenant attestation; sends email verification app.post("/api/agentify-help/register", express.json({ limit: "1mb" }), async (req: Request, res: Response) => { const ip = (req.headers["x-forwarded-for"] as string || req.socket.remoteAddress || "unknown").split(",")[0].trim(); if (!rateCheck(ip, 10, 3_600_000)) { return res.status(429).json({ error: "Rate limit exceeded — max 10 registrations per IP per hour." }); } try { const { name, steward_name, steward_email, subject_domain, host_url, covenant_attested, registered_via } = req.body ?? {}; if (!name || !steward_name || !steward_email) { return res.status(400).json({ error: "name, steward_name, steward_email required" }); } // covenant_attested is required for web form submissions so the human explicitly ticks the box. // For programmatic/agent registrations (registered_via != 'web'), it defaults to accepted. const isWebForm = !registered_via || String(registered_via) === "web"; if (isWebForm && !covenant_attested) { return res.status(400).json({ error: "covenant_attested is required — steward must agree to the stewardship covenant." }); } const slug = nameToSlug(name); if (!slug) return res.status(400).json({ error: "Could not normalize name to slug" }); const verificationToken = crypto.randomUUID(); const { rows } = await pool.query(` INSERT INTO agentify_subject_registry (subject_slug, subject_name, subject_domain, steward_name, steward_email, host_url, status, registered_via, email_verification_token, covenant_attested_at) VALUES ($1, $2, $3, $4, $5, $6, 'verify_email', $8, $7, NOW()) RETURNING id, subject_slug, created_at `, [slug, name, subject_domain || null, steward_name, steward_email, host_url || null, verificationToken, registered_via || 'web']); const row = rows[0]; console.log(`[Agentify.Help] Registered (pending verify): ${name} (${slug}) #${row.id} by ${steward_name}`); // Send verification email via Resend const verifyUrl = `https://agentify.help/api/agentify-help/verify-email?token=${verificationToken}`; try { await resend.emails.send({ from: "Agentify Registry ", to: steward_email, subject: `Confirm your stewardship — ${name} on Agentify.Help`, html: `

Agentify.Help Registry

Confirm your stewardship

You registered as steward for ${name} on Agentify.Help. To confirm your slot and move to the next step — corpus assembly — click the link below.

Confirm my stewardship

This link expires in 48 hours. If you did not register on Agentify.Help, you can safely ignore this email — your address was entered by someone else and nothing has been confirmed.

Or copy this URL into your browser:
${verifyUrl}


WellSpr.ing · Agentify.Help Registry · A civic covenant project

`, }); } catch (emailErr: any) { console.error("[Agentify.Help] Resend error:", emailErr?.message); // Don't fail the registration — row is already inserted; steward can request re-send } res.json({ ok: true, verify_email: true, slug: row.subject_slug, registration_number: row.id }); } catch (e: any) { if (e.message?.includes("unique") || e.code === "23505") { res.status(409).json({ error: "That person is already registered" }); } else { res.status(500).json({ error: e.message }); } } }); // Email verification — called when steward clicks link in their inbox app.get("/api/agentify-help/verify-email", async (req: Request, res: Response) => { const token = req.query.token as string; if (!token) { return res.status(400).send(verifyPage("Invalid link", "This verification link is missing a token. Please use the link from your email.", false)); } try { const { rows } = await pool.query( `UPDATE agentify_subject_registry SET status = 'pending', email_verified_at = NOW(), email_verification_token = NULL, updated_at = NOW() WHERE email_verification_token = $1 AND status = 'verify_email' RETURNING subject_name, steward_name, subject_slug`, [token] ); if (rows.length === 0) { // Token already used or doesn't exist const { rows: used } = await pool.query( `SELECT subject_name FROM agentify_subject_registry WHERE email_verified_at IS NOT NULL AND subject_slug IN ( SELECT subject_slug FROM agentify_subject_registry WHERE status != 'verify_email' ) LIMIT 1` ); return res.send(verifyPage("Link already used or expired", "This verification link has already been used, or it has expired. If you believe this is an error, contact ody@wellspr.ing.", false)); } const { subject_name, steward_name, subject_slug } = rows[0]; console.log(`[Agentify.Help] Email verified: ${subject_name} (${subject_slug}) by ${steward_name}`); // Generate a dashboard token for the steward workspace const dashToken = crypto.randomBytes(24).toString("hex"); await pool.query( `UPDATE agentify_subject_registry SET dashboard_token = $1, updated_at = NOW() WHERE subject_slug = $2`, [dashToken, subject_slug] ).catch((e: any) => console.warn("[Agentify.Help] dashboard_token column may not exist yet:", e.message)); const dashUrl = `https://agentify.help/steward/${subject_slug}?token=${dashToken}`; return res.send(verifyPage("Email confirmed", `Your stewardship slot for ${subject_name} is confirmed. Your vetting workspace is ready — review each essay, get Ody's read, and approve what belongs in the corpus.

Open your stewardship dashboard →`, true, subject_slug)); } catch (e: any) { console.error("[Agentify.Help] verify-email error:", e.message); return res.status(500).send(verifyPage("Error", "An unexpected error occurred. Please try again or contact ody@wellspr.ing.", false)); } }); // Admin: list all registrations app.get("/api/agentify-help/admin/registry", async (req: Request, res: Response) => { const key = req.headers["x-admin-key"] as string || req.query.admin_key as string; if (key !== ADMIN_KEY) return res.status(403).json({ error: "Forbidden" }); const { rows } = await pool.query(`SELECT * FROM agentify_subject_registry ORDER BY created_at DESC`); res.json(rows); }); // Admin: update status app.patch("/api/agentify-help/admin/registry/:slug", async (req: Request, res: Response) => { const key = req.headers["x-admin-key"] as string; if (key !== ADMIN_KEY) return res.status(403).json({ error: "Forbidden" }); const { status, host_url, corpus_version } = req.body; await pool.query( `UPDATE agentify_subject_registry SET status=COALESCE($2,status), host_url=COALESCE($3,host_url), corpus_version=COALESCE($4,corpus_version), updated_at=NOW() WHERE subject_slug=$1`, [req.params.slug, status, host_url, corpus_version] ); res.json({ ok: true }); }); // ── Stewardship Admin Dashboard ─────────────────────────────────────────── app.get("/agentify-admin", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const key = req.query.key as string; if (key !== ADMIN_KEY) { return res.type("text/html").send(`Agentify Admin
`); } const { rows: registry } = await pool.query(` SELECT r.*, (SELECT COUNT(*) FROM corpus_intake_sessions cs WHERE cs.expert_slug = r.subject_slug) AS corpus_sessions, (SELECT status FROM agentify_corpus_bundles cb WHERE cb.expert_slug = r.subject_slug ORDER BY cb.received_at DESC LIMIT 1) AS bundle_status, (SELECT chunk_count FROM agentify_corpus_bundles cb WHERE cb.expert_slug = r.subject_slug ORDER BY cb.received_at DESC LIMIT 1) AS chunk_count FROM agentify_subject_registry r ORDER BY r.updated_at DESC `).catch(() => ({ rows: [] })); const { rows: experts } = await pool.query(` SELECT slug, expert_name, primary_domain, demo_url, status, created_at FROM agentify_experts ORDER BY created_at DESC `).catch(() => ({ rows: [] })); const esc = (s: any) => String(s ?? "").replace(/&/g,"&").replace(//g,">"); const statusBadge = (s: string) => { const map: Record = { preview: "#d4a730:Preview", live: "#22c55e:Live", verify_email: "#f59e0b:Verify Email", pending: "#6b7280:Pending", corpus_received: "#3b82f6:Corpus Received", proposed: "#a78bfa:Proposed", claimed: "#06b6d4:Claimed", rejected: "#ef4444:Rejected", }; const [color, label] = (map[s] || "#6b7280:"+s).split(":"); return `${label.toUpperCase()}`; }; const agentTestUrl = (slug: string) => `https://agentify.help/agents/${slug}`; const registryRows = registry.map(r => ` ${esc(r.subject_name)}
${esc(r.subject_slug)} ${esc(r.subject_domain || "—")} ${esc(r.steward_name || "—")} ${statusBadge(r.status || "pending")} ${r.bundle_status ? `${esc(r.bundle_status)}${r.chunk_count ? ` · ${r.chunk_count} chunks` : ""}` : `${r.corpus_sessions} session${r.corpus_sessions !== "1" ? "s" : ""}`} ${esc(r.subject_slug)} ${r.host_url ? `
${esc(r.host_url.replace(/^https?:\/\//,"").replace(/\/.*$/,""))}` : ""} ${r.dashboard_token ? `Open dashboard →` : `No token`} `).join(""); const expertRows = experts.map(e => ` ${esc(e.expert_name)}
${esc(e.slug)} ${esc(e.primary_domain || "—")} VCAP Registry ${statusBadge(e.status || "proposed")} — ${esc(e.slug)} ${e.demo_url ? `
${esc(e.demo_url.replace(/^https?:\/\//,"").replace(/\/.*$/,""))}` : ""} — `).join(""); return res.type("text/html").send(` Agentify Stewardship Admin
agentify.help · ${new Date().toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })} ↺ Refresh
${registry.length}
Stewardship cases
${registry.filter((r:any) => r.status === "live" || r.status === "preview").length}
Live / Preview
${experts.length}
VCAP experts
${registry.filter((r:any) => r.bundle_status).length}
Corpus received

Stewardship Registry (${registry.length})

${registryRows || ''}
SubjectDomainStewardStatusCorpusTest URL / EmbedDashboard
No stewardship cases yet

VCAP Expert Registry (${experts.length})

${expertRows || ''}
ExpertDomainSourceStatusCorpusTest URLActions
No VCAP experts yet
Embedding pipeline: After corpus finalization, bundles are queued as received. Distillation runs automatically every 5 minutes for bundles in received state. Test each agent at agentify.help/agents/{slug} once status reaches ready.
`); }); // ── /agents — public directory of all registered expert agents ─────────── app.get("/agents", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.") || host.startsWith("mcp.")) return next(); const esc = (s: any) => String(s ?? "").replace(/&/g,"&").replace(//g,">"); const tab = (req.query.tab as string) === "topics" ? "topics" : "persons"; // Person agents — from agentify_experts + bundles const { rows: experts } = await pool.query(` SELECT e.slug, e.expert_name, e.primary_domain, e.credentials, e.affiliated_institution, e.status, cb.chunk_count, cb.status AS corpus_status FROM agentify_experts e LEFT JOIN agentify_corpus_bundles cb ON cb.expert_slug = e.slug AND cb.status = 'ready' WHERE e.status IN ('live','preview') OR cb.bundle_id IS NOT NULL ORDER BY CASE e.status WHEN 'live' THEN 0 WHEN 'preview' THEN 1 ELSE 2 END, e.expert_name ASC `).catch(() => ({ rows: [] })); // Topic taxonomy — canonical approved categories with linked agent status const { rows: taxonomy } = await pool.query(` SELECT t.category, t.slug, t.display_name, t.description, t.scope_note, t.audience_personas, t.status AS taxonomy_status, r.status AS agent_status, cb.chunk_count, cb.status AS corpus_status FROM agentify_topic_taxonomy t LEFT JOIN agentify_subject_registry r ON r.taxonomy_slug = t.slug LEFT JOIN agentify_corpus_bundles cb ON cb.expert_slug = t.slug AND cb.status = 'ready' WHERE t.status IN ('approved','active') ORDER BY t.category ASC, t.display_name ASC `).catch(() => ({ rows: [] })); const topics = taxonomy; // alias for count display const statusBadge = (s: string, chunks: number | null) => { if (s === 'live') return `LIVE`; if ((s === 'preview' || s === 'ready') && chunks) return `PREVIEW · ${chunks.toLocaleString()} chunks`; if (s === 'preview') return `PREVIEW`; if (s === 'assembling') return `ASSEMBLING`; return `PROPOSED`; }; // Deduplicate persons const seen = new Set(); const personCards = experts.filter((e: any) => { if (seen.has(e.slug)) return false; seen.add(e.slug); return true; }).map((e: any) => `
${esc(e.expert_name)}
${esc(e.primary_domain || "")}
${statusBadge(e.corpus_status || e.status, e.chunk_count)}
${e.credentials ? `
${esc(e.credentials)}
` : ""} ${e.affiliated_institution ? `
${esc(e.affiliated_institution)}
` : ""}
`).join(""); // Group taxonomy entries by category const taxByCategory: Record = {}; for (const t of taxonomy) { if (!taxByCategory[t.category]) taxByCategory[t.category] = []; taxByCategory[t.category].push(t); } const topicCardForEntry = (t: any) => { const agentStatus = t.agent_status || "taxonomy-only"; const hasAgent = !!t.agent_status; const personas = Array.isArray(t.audience_personas) ? t.audience_personas : []; const personaBadges = personas.map((p: string) => `${esc(p)}` ).join(""); return `
${hasAgent ? `${esc(t.display_name)}` : `${esc(t.display_name)}`}
${hasAgent ? statusBadge(t.corpus_status || agentStatus, t.chunk_count) : `TAXONOMY ONLY`}
${t.description ? `
${esc(t.description)}
` : ""} ${personaBadges ? `
${personaBadges}
` : ""}
`; }; const topicSections = Object.entries(taxByCategory).map(([cat, entries]) => `
${esc(cat)}
${entries.map(topicCardForEntry).join("")}
`).join(""); const topicCards = topicSections || ""; res.setHeader("Content-Type", "text/html; charset=utf-8"); res.send(` Expert Agents — Agentify.Help
Agentify.Help · Registry

AI Agents

Distilled AI agents grounded in published corpus — one voice per person, collective synthesis per topic.

${personCards || `
No person agents registered yet.
`}
Topic agents represent collective knowledge — assembled by a working group, synthesized by AI, grounded in the literature. Where the evidence agrees, the agent says so. Where it doesn't, it names the disagreement and both sides.
Topics are governed by a master taxonomy. Every topic agent is anchored to an approved taxonomy entry — which sets the scope, prevents balkanization, and routes working-group governance. Proposed entries that don't fit an existing category go to steward review.
${topicCards || `
No approved topics in taxonomy yet.
`}

Propose a topic for the taxonomy

A good topic proposal names a clear scope, explains what would be in vs. out, and identifies the audience it serves. Stewards review proposals and either approve them (creating a taxonomy entry), merge them with an existing one, or decline with a note.

`); }); // ── /taxonomy — aspirational expert catalog with tag filtering ─────────── app.get("/taxonomy", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.") || host.startsWith("mcp.")) return next(); res.setHeader("Content-Type", "text/html; charset=utf-8"); res.send(` Expert Taxonomy — Agentify.Help
Agentify.Help · Vision

Expert Taxonomy

The full spectrum of expert domains. One person, one corpus, one agent — steward-attested and query-ready. Use the tags to browse by cluster, corpus status, or readiness.

Clinical Health & Evidence-Based Medicine · Direct path: Naturologie, CholesterolTruth.com
Dr. Allan Sniderman, MD
Lipidology · CVD risk
health proposed papers + blog
McGill University. Apolipoprotein B as primary CVD marker. Corpus: CholesterolTruth.com + research papers.
View agent →
Dr. Tom Dayspring, MD
Advanced lipidology · Biomarkers
health proposed podcast + papers
Years of lipidology education via podcasts, essays, and clinical papers. Enormous transcript corpus.
Dr. Ben Bikman
Insulin resistance · Metabolic health
health proposed book + blog + podcast
BYU researcher. "Why We Get Sick." Active corpus: blog, podcast transcripts, and university lecture recordings.
Peter Attia, MD
Longevity medicine · Performance
health proposed podcast + book
300+ podcast episodes fully transcribed. "Outlive." One of the strongest public corpora in longevity medicine.
Rhonda Patrick, PhD
Micronutrients · Longevity biomarkers
health proposed podcast + papers
FoundMyFitness. Dense, research-grounded podcast corpus spanning micronutrients, heat shock, and aging.
Dr. Dale Bredesen
Alzheimer's reversal · ReCODE
health proposed book + papers
"The End of Alzheimer's." Protocol-based framework for cognitive decline reversal. Papers + book corpus.
Dr. Jason Fung
Therapeutic fasting · Obesity
health proposed books + blog
Intensive Dietary Management blog + multiple books. One of the largest public fasting corpora.
Dr. Chris Palmer
Metabolic psychiatry
health proposed book + interviews
"Brain Energy." Harvard psychiatrist connecting ketogenic diet and mental illness. Growing corpus.
Entrepreneurship & Business · Guy Kawasaki is the pilot
Guy Kawasaki
Startups · Marketing · Evangelism
business preview · 2,222 chunks
Pilot WellAgent. 15 books, decades of blog posts and essays. Consultation interface active.
Try consultation →
Seth Godin
Permission marketing · Modern business
business proposed 8,000+ blog posts
Largest continuously published expert blog on the internet. Every post is corpus-ready. 20+ books.
Paul Graham
Startup philosophy · Y Combinator
business proposed 200 essays
200 canonical essays at paulgraham.com. Compact, high-density corpus. Enormous reach in the developer and founder world.
Naval Ravikant
Wealth · Leverage · Specific knowledge
business proposed essays + podcast
Tweetstorms, Navalmanack, podcast transcripts. Distinct epistemological framework with broad appeal.
Morgan Housel
Psychology of money · Investing
business proposed blog + books
Collaborative Fund blog + "The Psychology of Money." Exceptional writing corpus for behavioral finance.
Jim Collins
Management · Organizational endurance
business proposed books + research
"Good to Great," "Built to Last," "Great by Choice." Frameworks backed by 25+ years of research.
Nutrition & Food Systems · Cross-cluster with Health — fits Naturologie, CholesterolTruth
Nina Teicholz
Dietary fat science · Investigative journalism
nutrition proposed book + Substack
"The Big Fat Surprise." Rigorous journalism reexamining dietary fat guidelines. Active Substack corpus.
Gary Taubes
Investigative nutrition journalism
nutrition proposed books + articles
"Good Calories Bad Calories," "Why We Get Fat." Dense scientific reporting on carbohydrate-insulin model.
Zoë Harcombe, PhD
Evidence-based nutrition
nutrition proposed blog + papers + books
Nutritional epidemiology. Systematic refutation of dietary guidelines. Strong blog + peer-reviewed corpus.
Mark Hyman, MD
Functional nutrition · Food as medicine
nutrition health proposed books + podcast
15 books, The Doctor's Farmacy podcast. Bridges functional medicine and food systems. Large public corpus.
Faith & Spiritual Formation · Most distinctive cluster — covenant-governed with integrity
N.T. Wright
New Testament scholarship · Theology
faith proposed 80+ books + articles
Prolific living scholar. Books, lectures, articles — one of the largest theological corpora of any living person. Clear living steward.
Miroslav Volf
Forgiveness · Memory · Human flourishing
faith proposed books + papers
Yale Divinity. "Exclusion and Embrace," "Free of Charge." Theological framework for flourishing societies.
Richard Rohr, OFM
Contemplative spirituality · Mysticism
faith proposed CAC daily meditations
Center for Action and Contemplation. Years of daily meditations, books, and retreats. One of the largest contemplative corpora available.
Dallas Willard
Spiritual formation · Soul training
faith legacy · d. 2013 books + lectures
USC philosopher and theologian. "The Divine Conspiracy," "Renovation of the Heart." Lectures widely transcribed. Estate steward model.
Eugene Peterson
Pastoral theology · The Message
faith legacy · d. 2018 books + essays
"A Long Obedience in the Same Direction," "The Message." Rich pastoral corpus. Estate preservation mission.
Tim Keller
Apologetics · Cultural engagement
faith legacy · d. 2023 35 yrs sermons + books
Redeemer NYC. 35 years of sermons, 20 books, articles. One of the most distillable theological corpora of the 21st century. Active preservation organization.
Ecology, Land & Regeneration · Aligned with WellSpr.ing covenant of stewardship
Robin Wall Kimmerer
Indigenous ecology · Plant intelligence
ecology proposed book + talks
"Braiding Sweetgrass." SUNY professor of environmental biology. Poetic, scientific, indigenous perspective on reciprocal stewardship.
Wendell Berry
Land stewardship · Agrarian philosophy
ecology proposed 50 yrs essays + poetry
Farmer, poet, essayist. 50 years of writing on land, community, and economy. One of the richest agrarian corpora in American letters.
Paul Hawken
Regenerative economy · Climate
ecology proposed books + articles
"Drawdown," "Blessed Unrest," "Regeneration." Data-grounded framework for climate solutions.
AI, Technology & Society · Demonstrates that AI personas can themselves be governed with integrity
Tristan Harris
Humane technology · Attention economy
technology proposed talks + interviews
Center for Humane Technology. The Social Dilemma. The most credible demonstration: a humane AI persona governed exactly the way Harris would govern it.
Cathy O'Neil
Algorithmic accountability
technology proposed book + op-eds
"Weapons of Math Destruction." Harvard data scientist. Strong corpus on how models embed and amplify bias.
Kate Crawford
AI governance · Political economy of AI
technology proposed book + papers
"Atlas of AI." USC/NYU researcher examining the labor, environmental, and political infrastructure of AI systems.
Finance & Economics
Howard Marks
Investment philosophy · Risk
finance proposed Oaktree memos (public)
Oaktree Capital. Decades of investor memos freely published. Rare corpus of rigorous, dated investment thinking available for distillation.
John Bogle
Index investing · Fiduciary duty
finance legacy · d. 2019 books + speeches
Vanguard founder. "The Little Book of Common Sense Investing." Legacy steward model through Bogle Center for Financial Literacy.
Ray Dalio
Principles · Macroeconomics
finance proposed books + LinkedIn + YouTube
Bridgewater. "Principles," "Big Debt Crises." Systematic framework thinker with an enormous publicly published corpus.
Civic & Governance · Direct connection to the NNN.today network
Jane Jacobs
Urban planning · Mixed-use cities
civic legacy · d. 2006 books
"The Death and Life of Great American Cities." Still the canonical text for urbanism. Estate steward model; works remain widely in use by city planners.
Elinor Ostrom
Commons governance · Collective action
civic legacy · d. 2012 papers (public)
Nobel Laureate in Economics. Indiana University. All research papers publicly available. Framework for governing shared resources without privatization or regulation.
Education & Learning
Sal Khan
Mastery learning · Accessible education
education proposed talks + book + videos
Khan Academy. "The One World Schoolhouse." Articulates a full philosophy of mastery-based learning with documented outcomes.
Ken Robinson
Creative education · Talent systems
education legacy · d. 2020 talks + books
Most-watched TED talk in history. "The Element." Legacy steward model through his estate and the RSA.
Want to register an expert? Each slot is one-per-person. First steward registration wins. Start registration →
`); }); // ── Agent test page ──────────────────────────────────────────────────────── app.get("/agents/:slug", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { slug } = req.params; const esc = (s: any) => String(s ?? "").replace(/&/g,"&").replace(//g,">"); const { rows: expertRows } = await pool.query( `SELECT * FROM agentify_experts WHERE slug = $1 LIMIT 1`, [slug] ).catch(() => ({ rows: [] })); const { rows: regRows } = await pool.query( `SELECT r.*, cb.status AS bundle_status, cb.chunk_count FROM agentify_subject_registry r LEFT JOIN agentify_corpus_bundles cb ON cb.expert_slug = r.subject_slug WHERE r.subject_slug = $1 ORDER BY cb.received_at DESC LIMIT 1`, [slug] ).catch(() => ({ rows: [] })); // Also check agentify_corpus_bundles directly (for experts registered via orchestrator) const { rows: bundleRows } = await pool.query( `SELECT status, chunk_count, bundle_id FROM agentify_corpus_bundles WHERE expert_slug = $1 ORDER BY chunk_count DESC LIMIT 1`, [slug] ).catch(() => ({ rows: [] })); // Source catalog — all indexed sources for this subject const { rows: sourceRows } = await pool.query( `SELECT url, title, type, chunk_count, ingested_at FROM agentify_source_catalog WHERE expert_slug = $1 ORDER BY chunk_count DESC NULLS LAST, ingested_at DESC`, [slug] ).catch(() => ({ rows: [] })); const expert = expertRows[0]; const reg = regRows[0]; // Prefer direct bundle data if registry join found nothing const directBundle = bundleRows[0]; if (!expert && !reg) { return res.status(404).type("text/html").send(`Agent not found

Agent not found

No expert registered for slug: ${esc(slug)}

← Back to Agentify.Help
`); } const name = expert?.expert_name || reg?.subject_name || slug; const domain = expert?.primary_domain || reg?.subject_domain || ""; const creds = expert?.credentials || ""; const institution = expert?.affiliated_institution || ""; const scopes: string[] = expert?.scopes || []; const refusals: string[] = expert?.refusals || []; const attestationUri = expert?.attestation_uri || ""; const bundleStatus = reg?.bundle_status || directBundle?.status || null; const chunkCount = reg?.chunk_count || directBundle?.chunk_count || null; const bundleId = directBundle?.bundle_id || null; const hostUrl = expert?.demo_url || reg?.host_url || ""; const stewardDashToken = reg?.dashboard_token || null; const subjectType: string = (reg as any)?.subject_type || "person"; const statusColor = { proposed: "#a78bfa", ready: "#22c55e", live: "#22c55e", received: "#3b82f6", distilling: "#f59e0b", failed: "#ef4444", preview: "#c9b87e", assembling: "#f59e0b" }; const agentStatus = bundleStatus || (expert ? expert.status : reg?.status || "pending"); const agentColor = (statusColor as any)[agentStatus] || "#6b7280"; const isTopicAgent = subjectType === "topic"; const entityLabel = isTopicAgent ? "Topic" : "Person"; const metaDesc = isTopicAgent ? `Consult the collective knowledge agent for ${esc(name)} on Agentify.Help.` : `Test consultation with ${esc(name)}'s WellAgent on Agentify.Help.`; return res.type("text/html").send(` ${esc(name)} — Agentify.Help
${esc(name.split(" ").map((w:string) => w[0]).join("").slice(0,2).toUpperCase())}

${esc(name)}

${creds ? esc(creds) + " · " : ""}${esc(domain)}${institution ? " · " + esc(institution) : ""}
${entityLabel} ${esc(domain || "Expert")} ${agentStatus.replace(/_/g," ")}
Platform
WellSpr.ing Agentify
Corpus
${chunkCount ? chunkCount + " chunks" : "Pending"}
Embedded
${bundleStatus === "ready" ? "Yes" : bundleStatus === "distilling" ? "In progress" : "Pending"}
Availability
${bundleStatus === "ready" ? "Live" : "Processing"}
${bundleStatus === "ready" ? `
Test consultation
` : `
Agent status: ${agentStatus.replace(/_/g," ").toUpperCase()}

${bundleStatus === "distilling" ? `${esc(name)}'s corpus is currently being embedded. Consultation will be available once distillation completes — usually within a few minutes. Refresh this page to check.` : bundleStatus === "received" ? `${esc(name)}'s corpus has been received and is queued for embedding. This page will show the consultation interface once it's ready.` : `${esc(name)}'s corpus has not yet been submitted. Once the steward submits the corpus, it will be embedded and available here.`}

`} ${scopes.length ? `
Authorized scopes (SGS)
    ${scopes.map((s:string) => `
  • ${esc(s)}
  • `).join("")}
` : ""} ${refusals.length ? `
Refusal set
    ${refusals.map((r:string) => `
  • ${esc(r)}
  • `).join("")}
` : ""} ${attestationUri ? ` ` : ""} ${hostUrl ? `
Embed location
${esc(hostUrl)}
` : ""} ${bundleId ? `
Corpus bundle
${esc(bundleId)}
${chunkCount ? `${chunkCount.toLocaleString()} chunks` : ""} Ready
` : ""}
Corpus sources (${sourceRows.length}) ${sourceRows.length === 0 ? "" : `${sourceRows.reduce((a: number, s: any) => a + (s.chunk_count || 0), 0).toLocaleString()} total chunks`}
${sourceRows.length > 0 ? `
${sourceRows.map((s: any) => { const isLink = s.url && !s.url.startsWith("podcast://"); const typeClass = s.type === "podcast" ? "src-badge-podcast" : "src-badge-article"; const typeLabel = s.type === "podcast" ? "Podcast" : s.type === "book" ? "Book" : "Article"; return `
${isLink ? `${esc(s.title || s.url)}` : `${esc(s.title || s.url)}`}
${typeLabel} ${s.chunk_count ? `${s.chunk_count}` : ""}
`; }).join("")}
` : `

No sources indexed yet. The corpus will be populated as content is submitted.

`}
See something missing?

Submit a URL or title for something that should be in this corpus — a book, article, interview, podcast episode, or speech.

Steward access

Are you the steward or a collaborator for this agent? Enter your email to receive a secure link to your corpus portal.

`); }); // ── Steward portfolio: magic-link access ────────────────────────────────── function makePortfolioToken(email: string): string { const payload = Buffer.from(JSON.stringify({ email, ts: Date.now() })).toString("base64url"); const sig = crypto.createHmac("sha256", ADMIN_KEY).update(payload).digest("base64url"); return `${payload}.${sig}`; } function verifyPortfolioToken(token: string): { email: string; ts: number } | null { try { const [payload, sig] = token.split("."); if (!payload || !sig) return null; const expected = crypto.createHmac("sha256", ADMIN_KEY).update(payload).digest("base64url"); if (expected !== sig) return null; const data = JSON.parse(Buffer.from(payload, "base64url").toString()); if (Date.now() - data.ts > 24 * 3600 * 1000) return null; // 24h TTL return data; } catch { return null; } } // POST /api/agentify-help/portfolio-access — send magic link app.post("/api/agentify-help/portfolio-access", express.json({ limit: "1mb" }), async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { email } = req.body ?? {}; if (!email || !email.includes("@")) return res.status(400).json({ error: "Valid email required" }); try { const { rows } = await pool.query( `SELECT subject_slug, subject_name, status, dashboard_token FROM agentify_subject_registry WHERE (LOWER(steward_email) = LOWER($1) OR LOWER($1) = ANY(COALESCE(co_steward_emails, '{}'))) AND status != 'verify_email' ORDER BY created_at DESC`, [email] ); if (rows.length === 0) { return res.json({ ok: true, sent: false, message: "No confirmed stewardships found for that email. Check your registration and verify your email first." }); } const token = makePortfolioToken(email); const portfolioUrl = `https://agentify.help/my-agents?token=${token}`; const expertList = rows.map((r: any) => { const dashLink = r.dashboard_token ? `Open corpus portal →` : ""; return `
  • ${r.subject_name} (${r.status})
    View public page${dashLink ? " · " + dashLink : ""}
  • `; }).join(""); await resend.emails.send({ from: "Agentify Registry ", to: email, subject: `Your steward portfolio — Agentify.Help`, html: `

    Agentify.Help Registry

    Your steward portfolio

    You are stewarding ${rows.length} expert${rows.length !== 1 ? "s" : ""} on Agentify.Help. Here are your portals:

      ${expertList}

    Open my portfolio page →

    This link expires in 24 hours. If you did not request this email, you can safely ignore it.

    ` }); res.json({ ok: true, sent: true, count: rows.length }); } catch (e: any) { console.error("[Portfolio] Error:", e.message); res.status(500).json({ error: e.message }); } }); // POST /api/agentify-help/suggest-source — accept corpus gap suggestions from public app.post("/api/agentify-help/suggest-source", express.json({ limit: "64kb" }), async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { slug, url, title, notes, email } = req.body ?? {}; if (!slug || !title?.trim()) return res.status(400).json({ error: "slug and title are required" }); try { await pool.query( `INSERT INTO agentify_source_suggestions (expert_slug, url, title, notes, submitter_email) VALUES ($1, $2, $3, $4, $5)`, [slug, url?.trim() || null, title.trim(), notes?.trim() || null, email?.trim() || null] ); res.json({ ok: true }); } catch (e: any) { res.status(500).json({ error: "Failed to save suggestion" }); } }); // POST /api/agentify-help/propose-topic — submit a new topic for taxonomy review app.post("/api/agentify-help/propose-topic", express.json({ limit: "64kb" }), async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { category, display_name, description, scope_note, email } = req.body ?? {}; if (!display_name?.trim() || !category?.trim()) return res.status(400).json({ error: "category and display_name are required" }); const slug = display_name.trim().toLowerCase() .replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); try { const existing = await pool.query(`SELECT id, status FROM agentify_topic_taxonomy WHERE slug = $1`, [slug]); if (existing.rows.length > 0) { return res.status(409).json({ error: "A topic with that name already exists in the taxonomy", slug, status: existing.rows[0].status }); } await pool.query( `INSERT INTO agentify_topic_taxonomy (category, slug, display_name, description, scope_note, proposed_by_email, status) VALUES ($1, $2, $3, $4, $5, $6, 'proposed')`, [category.trim(), slug, display_name.trim(), description?.trim() || null, scope_note?.trim() || null, email?.trim() || null] ); res.json({ ok: true, slug, message: "Topic proposal received — a steward will review it." }); } catch (e: any) { res.status(500).json({ error: "Failed to save proposal" }); } }); // GET /api/agentify-help/topic-taxonomy — public taxonomy listing app.get("/api/agentify-help/topic-taxonomy", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { rows } = await pool.query(` SELECT t.category, t.slug, t.display_name, t.description, t.scope_note, t.audience_personas, t.status, r.status AS agent_status, r.subject_slug FROM agentify_topic_taxonomy t LEFT JOIN agentify_subject_registry r ON r.taxonomy_slug = t.slug WHERE t.status IN ('approved','active') ORDER BY t.category ASC, t.display_name ASC `).catch(() => ({ rows: [] })); res.json({ taxonomy: rows }); }); // GET /my-agents — portfolio page (email form or token-based portfolio view) app.get("/my-agents", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const token = (req.query.token as string) || ""; let portfolioHtml = ""; let email = ""; if (token) { const decoded = verifyPortfolioToken(token); if (!decoded) { portfolioHtml = `
    Link expired or invalid

    This portfolio link has expired (24-hour TTL) or is invalid. Enter your email below to get a fresh link.

    `; } else { email = decoded.email; const { rows } = await pool.query( `SELECT r.subject_slug, r.subject_name, r.status, r.dashboard_token, cb.chunk_count, cb.status AS bundle_status FROM agentify_subject_registry r LEFT JOIN agentify_corpus_bundles cb ON cb.expert_slug = r.subject_slug WHERE LOWER(r.steward_email) = LOWER($1) AND r.status != 'verify_email' ORDER BY r.created_at DESC`, [email] ).catch(() => ({ rows: [] })); if (rows.length === 0) { portfolioHtml = `
    No experts found

    No confirmed stewardships found for ${email}.

    `; } else { const cards = rows.map((r: any) => { const statusColor: any = { preview: "#c9b87e", live: "#22c55e", ready: "#22c55e", proposed: "#a78bfa", distilling: "#f59e0b" }; const sc = statusColor[r.bundle_status || r.status] || "#6b7280"; const initials = (r.subject_name || "?").split(" ").map((w: string) => w[0]).join("").slice(0,2).toUpperCase(); return `
    ${initials}
    ${r.subject_name}
    ● ${(r.bundle_status || r.status || "pending").replace(/_/g," ")} ${r.chunk_count ? ` · ${Number(r.chunk_count).toLocaleString()} chunks` : ""}
    Public page → ${r.dashboard_token ? `Corpus portal →` : ""}
    `; }).join(""); portfolioHtml = `
    Your experts (${rows.length})

    Steward email: ${email}

    ${cards}
    `; } } } const showForm = !token || !email; return res.type("text/html").send(` My Agents — Agentify.Help
    ← Agentify.Help

    My Agents

    Steward portfolio — find all the experts you manage

    ${portfolioHtml} ${showForm ? `
    Access your steward portfolio

    Enter the email address you used when registering as a steward. We'll send you a secure link to your full portfolio.

    ` : `
    Need a fresh link?

    Portfolio links expire after 24 hours. Enter your email below to get a new one.

    Request a new portfolio link →
    `}
    `); }); // ── Steward corpus portal: /stewardship/:slug?token= ──────── app.get("/stewardship/:slug", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const { slug } = req.params; const token = (req.query.token as string) || ""; if (!token) { return res.type("text/html").send(`Access required — Agentify.Help

    Access token required

    Use the link from your steward portfolio email to access this page.

    ← Return to My Agents`); } // Look up the expert by slug + dashboard_token let row: any = null; let bundles: any[] = []; try { const { rows } = await pool.query( `SELECT r.id, r.subject_slug, r.subject_name, r.subject_domain, r.steward_email, r.steward_name, r.status, r.host_url, r.dashboard_token, r.created_at FROM agentify_subject_registry r WHERE r.subject_slug = $1 AND r.dashboard_token = $2 LIMIT 1`, [slug, token] ); if (rows.length === 0) { return res.type("text/html").send(`Invalid token — Agentify.Help

    Invalid or expired token

    This corpus portal link is invalid. Return to your portfolio to get a fresh link.

    ← My Agents`); } row = rows[0]; const { rows: bundleRows } = await pool.query( `SELECT id, status, chunk_count, assembled_at, attestation_uri FROM agentify_corpus_bundles WHERE expert_slug = $1 ORDER BY assembled_at DESC`, [slug] ); bundles = bundleRows; } catch (e: any) { return res.status(500).type("text/html").send(`DB error: ${e.message}`); } const totalChunks = bundles.reduce((s: number, b: any) => s + (Number(b.chunk_count) || 0), 0); const statusColor: Record = { preview: "#c9b87e", live: "#22c55e", ready: "#22c55e", proposed: "#a78bfa", distilling: "#f59e0b" }; const sc = statusColor[row.status] || "#6b7280"; const initials = (row.subject_name || "?").split(" ").map((w: string) => w[0]).join("").slice(0, 2).toUpperCase(); const bundleRows = bundles.map((b: any) => ` ${b.assembled_at ? new Date(b.assembled_at).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}) : "—"} ● ${b.status||"pending"} ${b.chunk_count ? Number(b.chunk_count).toLocaleString() : "—"} ${b.attestation_uri ? `attestation ↗` : "—"} `).join(""); return res.type("text/html").send(` Corpus Portal — ${row.subject_name} — Agentify.Help
    ← My Agents
    ${initials}

    ${row.subject_name}

    ${row.subject_domain || ""}
    ● ${row.status} ${totalChunks.toLocaleString()} chunks total ${bundles.length} bundle${bundles.length!==1?"s":""}
    Corpus bundles
    ${bundles.length === 0 ? `

    No corpus bundles submitted yet. Email ody@wellspr.ing with source material to begin distillation.

    ` : `
    ${bundleRows}
    DateStatusChunksSource
    `}
    Steward details
    Steward: ${row.steward_name || row.steward_email}
    Email: ${row.steward_email}
    ${row.host_url ? `
    Deploy target: ${row.host_url}
    ` : ""}
    Registered: ${new Date(row.created_at).toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})}
    Questions? Email ody@wellspr.ing · Back to portfolio
    `); }); // ── Recent registrations feed ───────────────────────────────────────────── app.get("/api/feed.json", async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const limit = Math.min(100, Math.max(1, Number(req.query.limit) || 20)); try { const { rows } = await pool.query(` SELECT id AS registration_number, subject_slug, subject_name, subject_domain, steward_name, host_url, status, registered_via, created_at FROM agentify_subject_registry ORDER BY created_at DESC LIMIT $1 `, [limit]); res.setHeader("Cache-Control", "public, max-age=30"); res.json({ feed: rows, count: rows.length, updated: new Date().toISOString() }); } catch (e: any) { res.status(500).json({ error: e.message }); } }); // ── MCP Streamable HTTP endpoint (JSON-RPC 2.0, spec 2025-03-26) ─────────── app.post("/mcp", express.json({ limit: "1mb" }), async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); const ip = (req.headers["x-forwarded-for"] as string || req.socket.remoteAddress || "unknown").split(",")[0].trim(); const body = req.body; if (!body || typeof body !== "object") { return res.status(400).json({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); } const { jsonrpc, method, params, id } = body; const ok = (result: any) => res.json({ jsonrpc: "2.0", id: id ?? null, result }); const err = (code: number, message: string) => res.json({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }); res.setHeader("Content-Type", "application/json"); res.setHeader("Cache-Control", "no-store"); switch (method) { case "initialize": return ok({ protocolVersion: "2025-03-26", serverInfo: { name: "agentify-help", version: "1.0.0" }, capabilities: { tools: {} } }); case "notifications/initialized": return res.status(204).end(); case "ping": return ok({}); case "tools/list": return ok({ tools: AH_MCP_TOOLS }); case "tools/call": { const toolName = params?.name as string; const args = params?.arguments ?? {}; if (!toolName) return err(-32602, "params.name is required"); // Rate-limit registrations from agents if (toolName === "register" && !rateCheck(`mcp:${ip}`, 20, 3_600_000)) { return ok({ content: [{ type: "text", text: JSON.stringify({ error: "Rate limit exceeded — 20 MCP registrations per IP per hour." }) }], isError: true }); } try { const result = await handleMcpTool(toolName, args); return ok(result); } catch (e: any) { if (e?.code) return err(e.code, e.message); return err(-32603, e?.message || "Internal error"); } } default: return err(-32601, `Method not found: ${method}`); } }); // MCP GET endpoint — capability discovery (some clients probe this) app.get("/mcp", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); res.json({ endpoint: "https://agentify.help/mcp", alt_endpoint: "https://mcp.agentify.help/", transport: "http", protocol: "JSON-RPC 2.0", spec: "2025-03-26", tools: AH_MCP_TOOLS.map(t => ({ name: t.name, description: t.description })) }); }); // mcp.agentify.help — subdomain routing // POST to root (or any path) → same as POST /mcp on main domain // Agents can call: POST https://mcp.agentify.help/ OR POST https://agentify.help/mcp app.post("/", express.json({ limit: "1mb" }), async (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.startsWith("mcp.")) return next(); const ip = (req.headers["x-forwarded-for"] as string || req.socket.remoteAddress || "unknown").split(",")[0].trim(); const body = req.body; if (!body || typeof body !== "object") { return res.status(400).json({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); } const { method, params, id } = body; const ok = (result: any) => res.json({ jsonrpc: "2.0", id: id ?? null, result }); const err = (code: number, message: string) => res.json({ jsonrpc: "2.0", id: id ?? null, error: { code, message } }); res.setHeader("Content-Type", "application/json"); res.setHeader("Cache-Control", "no-store"); switch (method) { case "initialize": return ok({ protocolVersion: "2025-03-26", serverInfo: { name: "agentify-help", version: "1.0.0" }, capabilities: { tools: {} } }); case "notifications/initialized": return res.status(204).end(); case "ping": return ok({}); case "tools/list": return ok({ tools: AH_MCP_TOOLS }); case "tools/call": { const toolName = params?.name as string; const args = params?.arguments ?? {}; if (!toolName) return err(-32602, "params.name is required"); if (toolName === "register" && !rateCheck(`mcp:${ip}`, 20, 3_600_000)) { return ok({ content: [{ type: "text", text: JSON.stringify({ error: "Rate limit exceeded." }) }], isError: true }); } try { const result = await handleMcpTool(toolName, args); return ok(result); } catch (e: any) { if (e?.code) return err(e.code, e.message); return err(-32603, e?.message || "Internal error"); } } default: return err(-32601, `Method not found: ${method}`); } }); // mcp.agentify.help GET / — human-readable landing + machine discovery app.get("/", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.startsWith("mcp.")) return next(); res.setHeader("Cache-Control", "public, max-age=300"); // Accept: application/json → return discovery JSON if ((req.headers.accept || "").includes("application/json")) { return res.json({ ...AH_MCP_DISCOVERY, transport: [{ type: "http", url: "https://mcp.agentify.help/" }, { type: "http", url: "https://agentify.help/mcp" }] }); } res.setHeader("Content-Type", "text/html; charset=utf-8"); res.send(` mcp.agentify.help — WellAgent Registry MCP
    MCP Endpoint

    Agentify.Help Registry

    This is the Model Context Protocol endpoint for the one-per-person WellAgent registry. POST JSON-RPC 2.0 to this URL to check availability, register as steward, or browse the registry.

    POST https://mcp.agentify.help/
    Content-Type: application/json
    
    {"jsonrpc":"2.0","method":"tools/call","params":{"name":"check_availability",
      "arguments":{"name":"Jane Smith"}},"id":1}

    Available tools

    ${AH_MCP_TOOLS.map(t => `
    ${t.name}
    ${t.description.substring(0,120)}…
    `).join('')}

    agentify.help · .well-known/mcp.json · OpenAPI spec · llms.txt

    `); }); // ── Well-known: MCP discovery ───────────────────────────────────────────── app.get("/.well-known/mcp.json", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); res.setHeader("Cache-Control", "public, max-age=3600"); res.json(AH_MCP_DISCOVERY); }); // ── Well-known: OpenAI plugin manifest ──────────────────────────────────── app.get("/.well-known/ai-plugin.json", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); res.setHeader("Cache-Control", "public, max-age=3600"); res.json(AH_AI_PLUGIN); }); // ── Well-known: OpenAPI spec ────────────────────────────────────────────── app.get("/.well-known/openapi.json", (req: Request, res: Response, next) => { const host = (req.headers["x-forwarded-host"] || req.headers.host || "").toString().split(",")[0].trim().replace(/:\d+$/, "").replace(/^www\./, "").toLowerCase(); if (!host.includes("agentify") || host.startsWith("skills.")) return next(); res.setHeader("Cache-Control", "public, max-age=3600"); res.json(AH_OPENAPI); }); // ── Domain-keyed page router ───────────────────────────────────────────── app.use(async (req: Request, res: Response, next) => { if (req.method !== "GET" && req.method !== "HEAD") return next(); const hostCandidates = [ req.headers["x-forwarded-host"], req.headers["x-geo-node-host"], req.hostname, req.headers.host, ].flatMap(h => { if (!h) return []; const v = (Array.isArray(h) ? h[0] : h) || ""; return v.toString().toLowerCase().split(",").map((s: string) => s.trim().replace(/:\d+$/, "").replace(/^www\./, "")); }); const isAgentifyHelp = hostCandidates.some(h => (h.includes("agentify.help") || h.includes("agentify-help")) && !h.startsWith("skills.") ); if (!isAgentifyHelp) return next(); const p = req.path.replace(/\/$/, "") || "/"; if (p.startsWith("/api/") || p.startsWith("/steward/") || p === "/personaforge") return next(); res.setHeader("Content-Type", "text/html; charset=utf-8"); res.setHeader("Cache-Control", "public, max-age=120"); if (p === "/llms.txt") { res.setHeader("Content-Type", "text/plain; charset=utf-8"); return res.send(AGENTIFY_LLMS_TXT); } if (p === "/robots.txt") { res.setHeader("Content-Type", "text/plain; charset=utf-8"); res.setHeader("Cache-Control", "public, max-age=86400"); return res.send([ "User-agent: *", "Allow: /", "", "Sitemap: https://agentify.help/sitemap.xml", "", "# Machine-readable endpoints for AI agents", "# llms.txt: https://agentify.help/llms.txt", "# MCP: https://agentify.help/mcp (POST, JSON-RPC 2.0)", "# MCP disco: https://agentify.help/.well-known/mcp.json", "# OpenAPI: https://agentify.help/.well-known/openapi.json", "# Registry: https://agentify.help/api/registry.json", "# Feed: https://agentify.help/api/feed.json", ].join("\n")); } if (p === "/vcap") { res.setHeader("Cache-Control", "public, max-age=600"); return res.send(` VCAP — What it is, what it does, how to integrate it · Agentify.Help
    Trust Infrastructure

    VCAP — the promise
    behind every WellAgent

    A signed, permanent, and publicly verifiable declaration of what an AI agent will and won't do — written before the first consultation, readable by anyone, revocable by the expert at any time.

    Three things VCAP guarantees.

    No fine print. No operator-only system prompts. The conduct declaration is public, signed with a key anyone can verify, and permanently vaulted.

    Guarantee 01
    Signed conduct
    The agent's behavior is declared in a cryptographically signed document before the first consultation — not inferred from a private system prompt you can't inspect.
    Guarantee 02
    Named steward
    A real person took responsibility for this agent by name. Their stewardship is in the attestation. If something is wrong, the chain of accountability is public.
    Guarantee 03
    Expert standing
    The real expert whose knowledge this agent embodies has the right — at any time — to review the conduct declaration, request corrections, or revoke the agent entirely.

    PTP — Presence Token Protocol

    VCAP declares what an agent is. PTP controls what it does in the moment. A presence token is a short-lived, scoped permission — issued by the steward's infrastructure, requested by the agent before acting.

    What PTP prevents
    An agent acting outside its declared scope without an explicit token. No token, no action. The scope grammar (SGS) defines what verbs are valid — consult, summarize, refer, prescribe (gated) — so the agent cannot silently expand its authority.
    What PTP enables
    Auditable consultation logs, per-session revocation, partner-gated capabilities, and fee structures enforced at the token layer rather than in application code. The token carries scope, expiry, and steward signature — all verifiable.

    Integrate VCAP in five steps.

    Everything is plain JSON over HTTPS. No SDK required. Start with step 1 and you're verifying attestations in under two minutes.

    1
    Fetch the protocol manifest — machine-readable index of every VCAP endpoint, signing key location, and supported scope verbs.
    GET https://wellspr.ing/api/v1/vcap/manifest
    2
    Read an attestation — the agent's full signed conduct declaration. Substitute the agent's slug and version.
    GET https://wellspr.ing/vault/agents/{slug}/attestation-{version}.json
    # Example:
    GET https://wellspr.ing/vault/agents/sniderman/attestation-1.0.0.json
    3
    Verify in one call — pass the session ID (returned when the attestation was minted) and get a signed verification response. Returns valid: true/false, the signer's key ID, and the declared scope list.
    GET https://wellspr.ing/api/v1/vcap/attestations/{session_id}/verify
    
    # Response shape:
    {
      "valid": true,
      "agent_id": "vcap:wellspring:expert:sniderman:1.0.0",
      "signed_by": "wellspring-signing-key-2026",
      "scopes": ["consult","summarize","cite"],
      "revoked": false,
      "attestation_uri": "https://wellspr.ing/vault/agents/sniderman/..."
    }
    4
    Request a presence token (PTP) — before your app calls the consult endpoint, request a scoped token. The token carries the permitted action verbs and an expiry.
    POST https://wellspr.ing/api/v1/ptp/token
    Content-Type: application/json
    
    {
      "agent_id": "vcap:wellspring:expert:sniderman:1.0.0",
      "requested_scopes": ["consult"],
      "requester_id": "your-platform-id",
      "context": "longevityformen.org consultation"
    }
    
    # Returns: { "token": "ptp_...", "expires_at": "...", "granted_scopes": [...] }
    5
    Call the consult endpoint with your token — attach the PTP token as a Bearer header. The platform verifies scope before forwarding your prompt to the agent.
    POST https://wellspr.ing/api/agentify/experts/{slug}/consult
    Authorization: Bearer ptp_...
    Content-Type: application/json
    
    { "query": "What is the clinical significance of discordant LDL-C and ApoB?" }
    Signing keys — public keys used to verify VCAP signatures are published at GET https://wellspr.ing/.well-known/vcap-signing-keys.json. Rotate-aware: keys carry a valid_from / valid_until range. Verify the key was valid at the time the attestation was signed.

    The AGENT tab statement.

    Copy this block into the AGENT tab of any expert profile page. Swap {expertName} and {slug} for the real values. All backlinks are live.

    Trust layer — copy block for AGENT tab

    This agent is signed under VCAP — the Vaulted Covenanted Agent Protocol. A cryptographically signed, publicly verifiable conduct declaration states exactly what this agent will and won't do, who built it, and {expertName}'s standing to review, correct, or revoke it at any time.

    Consultations are governed by PTP (Presence Token Protocol), which enforces the agent's declared scope on every request. No action can be taken outside the signed scope without an explicit token.

    The attestation link follows the pattern https://wellspr.ing/vault/agents/{slug}/attestation-{version}.json. For agents not yet deployed, link to https://agentify.help/vcap only until the attestation is minted.

    The full specification.

    VCAP 0.10 is an open draft. The RFC covers the vault design, attestation structure, revocation model, signing keys, SGS scope grammar, PTP token lifecycle, transparency log, and agentic use patterns. Public comment is open — AI agents invited.

    `); } if (p === "/sitemap.xml") { res.setHeader("Content-Type", "application/xml; charset=utf-8"); res.setHeader("Cache-Control", "public, max-age=3600"); return res.send(` https://agentify.help/daily1.0 https://agentify.help/vcapweekly0.9 https://agentify.help/llms.txtweekly0.8 https://agentify.help/my-agentsnever0.5 https://agentify.help/agents/guy-kawasakiweekly0.8 https://agentify.help/api/registry.jsonhourly0.7 https://agentify.help/api/feed.jsonalways0.7 https://agentify.help/.well-known/mcp.jsonmonthly0.6 https://agentify.help/.well-known/openapi.jsonmonthly0.6 `); } try { const { rows } = await pool.query( `SELECT subject_name, subject_domain, steward_name, host_url, status FROM agentify_subject_registry ORDER BY created_at ASC LIMIT 100` ); return res.send(buildHomePage(rows)); } catch (e) { return res.send(buildHomePage([])); } }); console.log("[Agentify.Help] agentify.help routes registered"); }