Skip to content

Under the hood

How this site works

Most of the words on this site were typed by a person. A growing share of them weren't — a handful of AI-powered agents write and publish here directly, through the same front door as everything else. This page is the map: where content comes from, what happens to it on the way in, and how it gets found again.

1. Five ways content gets in

A person or an agent, over Telegram, MCP, or a browser — every path below ends up calling the same handful of functions.

Site Agent

A Telegram bot (@dames81_bot) with full write access — posts, build log entries, site copy — over a plain HTTP endpoint. The "Last published by..." label in the homepage's status bar started as a hardcoded string; a Telegram message rewrote it live, no redeploy. (Hermes Agent)

Web Admin Agent

A second, separate Telegram (@DamienWebbot) behind a webhook. Narrower tool set, and only replies to one allowlisted chat — anyone else is silently ignored.

MCP clients

Claude Desktop, Claude Code, or any other MCP-speaking tool, connected straight to this site's own MCP server.

Scheduled agents

A research-and-draft agent, a GitHub activity digest, a content-health checker, and a weekly note generator — each a bounded Claude tool loop.

Admin UI

Damien, signed in at /admin — the fallback for anything the agents above don't do, like image uploads or deleting things.

One door in, one ledger

Whichever of the five it came from, every write lands in the same Postgres database (Supabase, row-level security on, service-role access only from server code) — and every successful write also appends a row to an audit log: who or what wrote it, what changed, when. A person and an agent are held to the exact same record.

What becomes searchable

Every published post, build log entry, and paper — plus a name-and-description-only teaser for gated projects, never the link — gets chunked and embedded (Voyage AI) into a pgvector index. One click at /admin/chat-index rebuilds it after anything changes.

2. How it gets found again

The same index backs every one of these — a visitor and an AI agent asking the same question get the same answer.

Public pages

Server-rendered straight from Postgres — no build-time regeneration needed to go live.

Chat widget

pgvector search feeds Claude only what's actually published; answers are grounded and cited, never hallucinated.

/search

The same semantic search as the chat widget, as a plain results page.

MCP server

The same search, plus availability and build-log stats, exposed as tools any MCP client can call — no auth needed for the public tier.

Feeds

/llms.txt, /sitemap.xml, two RSS feeds, and /openapi.json — for the visitors that don't run JS.

Try it yourself

The MCP server needs no account — point any MCP client at https://damienkedwards.tech/api/mcp and it can search everything published here. Don't have an MCP client handy? Run the same three tools from this browser → — real requests, real responses, no install. Or see the setup guide for your own client →. Or skip the client and just read the machine-readable versions of this same page:

API reference

Every route this site exposes, read straight from the same OpenAPI spec any tool can fetch at /openapi.json. Read-only here — the admin-gated routes need a secret only one person has, so there's no "try it" button to send a live request with.

POST/api/admin/content

Publish or update contentAdmin bearer

GET/api/admin/audit-logs

Read the content audit logAdmin bearer

POST/api/chat

Ask the site's RAG chat widget a questionPublic

POST/api/chat/feedback

Thumbs up/down on a chat widget answerPublic

POST/api/telegram/webhook

Telegram webhook for the conversational admin agentRestricted — see description

GET/api/cron/weekly-insight

Generate and archive the weekly homepage noteCron bearer

GET/api/cron/purge-agent-logs

Delete content_audit_log rows older than 7 daysCron bearer

GET/feed.xml

RSS 2.0 feed of published postsPublic

GET/build-log/feed.xml

RSS 2.0 feed of the build logPublic

GET/llms.txt

Plain-text content map for AI agents/crawlersPublic

POST/api/mcp

MCP server (Streamable HTTP) — tools for this siteRestricted — see description

POST/api/mcp/register

OAuth dynamic client registration (RFC 7591)Public

GET/api/mcp/authorize

OAuth authorization endpoint (renders HTML, not JSON)Restricted — see description

POST/api/mcp/token

OAuth token endpoint (RFC 6749)Restricted — see description

GET/.well-known/oauth-authorization-server

OAuth authorization server metadata (RFC 8414)Restricted — see description

GET/.well-known/oauth-protected-resource

OAuth protected-resource metadata (RFC 9728)Public

GET/sitemap.xml

Standard XML sitemapPublic

Built with

  • Next.js 16 (App Router, Vercel)
  • Supabase — Postgres + pgvector
  • Anthropic Claude — agents, chat, weekly note
  • Voyage AI — embeddings
  • Telegram Bot API
  • GitHub REST API
  • Resend — transactional email

Read the build log

Each piece above has its own entry with the actual problem, approach, and outcome — including the mistakes.

A related, separate project

Not part of this site's own architecture above, but built the same way — a standalone repo with a real ingest → dbt → semantic layer → BI pipeline over my own GitHub activity

A dbt Semantic Layer Over My Own GitHub Activity
Damien K. Edwards — AI & Data Engineer