Hosted service agent readiness

This runbook owns the agent-discovery surface for the hosted public services:

  • https://pm-cli.unbrained.dev is implemented by the private website-server/ companion;
  • https://pm-web.unbrained.dev is implemented at the hosted Caddy edge plus a private HTML overlay;
  • https://pm-mcp.unbrained.dev is the real remote MCP transport; and
  • https://auth.unbrained.dev is the real Authentik OAuth/OIDC authorization server.

The public pm-cli and pm-web package repositories are not deployment configuration. Do not add hosted domains, operator metadata, DNS credentials, IndexNow keys, or private-service overlays to those repositories.

Published discovery surface

Both hosted domains publish or negotiate:

  • robots.txt, sitemap discovery, AI crawler rules, and Content Signals;
  • Markdown for the homepage via Accept: text/markdown;
  • API Catalog and OpenAPI discovery;
  • OAuth/OIDC authorization-server and RFC 9728 protected-resource metadata;
  • /auth.md with the supported interactive verified-email registration path;
  • MCP Server Card, A2A Agent Card, and Agent Skills metadata; and
  • WebMCP tools registered during homepage load.

The pm-web WebMCP script is deliberately injected by website-server/src/routes/hosted-overlays.ts. Caddy routes only the exact pm-web homepage through that private renderer. The renderer fetches the public upstream HTML and injects read-only tools that read public discovery documents; it never reads a workspace, user record, session, or token.

OAuth metadata must mirror the real Authentik providers:

  • pm-web issuer: https://auth.unbrained.dev/application/o/pm-web/;
  • hosted MCP issuer: https://auth.unbrained.dev/application/o/pm-gpt/.

Do not advertise dynamic client registration, anonymous credentials, or ID-JAG exchange unless those flows are actually implemented and verified. Current registration is interactive Authentik enrollment with verified email and predefined clients.

DNS-AID and DNSSEC

DNS-AID records live in the Cloudflare-managed unbrained.dev public zone, not in either application repository. On 2026-07-19, a scoped CLOUDFLARE_API_TOKEN successfully published these DNS-only, TTL 3600, ServiceMode SVCB records. Every record declares mandatory="alpn,port" and port="443":

Owner Target ALPN
_index._agents.pm-cli.unbrained.dev pm-cli.unbrained.dev. h2
_a2a._agents.pm-cli.unbrained.dev pm-cli.unbrained.dev. a2a,h2
_mcp._agents.pm-cli.unbrained.dev pm-mcp.unbrained.dev. mcp,h2
_index._agents.pm-web.unbrained.dev pm-web.unbrained.dev. h2
_a2a._agents.pm-web.unbrained.dev pm-web.unbrained.dev. a2a,h2
_mcp._agents.pm-web.unbrained.dev pm-mcp.unbrained.dev. mcp,h2

The Caddy .env also contains CLOUDFLARE_ACCESS_KEY_ID and CLOUDFLARE_SECRET_ACCESS_KEY. Those are separate S3-style credentials and are not used for DNS record or DNSSEC operations. Never print any credential value or store it in pm history. Verify an account-scoped token through the required zone endpoints; /user/tokens/verify can return 401 while zone listing, DNS records, and DNSSEC calls are correctly authorized.

Cloudflare signing is enabled and publishes DNSKEY/CDNSKEY/CDS data, but the zone is not yet authenticated. Cloudflare reports pending because IONOS is the registrar and the .dev parent currently has no DS record. IONOS documents that external-nameserver DNSSEC must be requested from customer service. Send [email protected] the subject Manual DS record required for external DNS provider and use this DS value:

unbrained.dev. 3600 IN DS 2371 13 2 F43A211BE1E377B6602EBC7B6CA6896011B338D5B7994BB41DEE070CF80A6C95

The full IONOS extensions.secDns request payload, including the public key, is maintained in /home/steve/caddy/docs/OPERATIONS.md. Until the DS record resolves, the live checker correctly reports 14/15 for each domain with only dnsAid failing DNSSEC validation. Do not claim 100% until the validating-resolver and scanner checks both pass.

Deployment and verification

cd /home/steve/container/pm-cli
npm --prefix website-server run typecheck
npm --prefix website-server test
docker compose build website
docker compose up -d website
docker compose ps website pm-web

cd /home/steve/caddy
./scripts/validate-config.sh
./scripts/reload-caddy.sh

cd /home/steve/container/pm-cli
./scripts/check-agent-readiness.sh
git -C fleet/pm-web status --short

The last command must remain empty. Record endpoint status, scan results, DNSSEC validation, changed files, and exact verification commands in the parent pm feature and its child tasks before closing them.

If Docker Hub/npm lookup fails but this change adds no dependency, an offline application-layer image may reuse the last complete production image after local typecheck, tests, and compilation:

docker build -f website-server/Dockerfile.deploy -t pm-cli-website-agentready .
docker tag pm-cli-website-agentready pm-cli-website:latest
docker compose up -d --no-build website

Do not use this fallback when package.json or package-lock.json changed.


Agent Readiness local
Ein Problem melden