Hosted service agent readiness
This runbook owns the agent-discovery surface for the hosted public services:
https://pm-cli.unbrained.devis implemented by the privatewebsite-server/companion;https://pm-web.unbrained.devis implemented at the hosted Caddy edge plus a private HTML overlay;https://pm-mcp.unbrained.devis the real remote MCP transport; andhttps://auth.unbrained.devis 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.mdwith 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.