Capabilities
Two capability surfaces — the service manifest and the runtime contract — and how to feature-detect.
Two surfaces, two questions
| Surface | Answers | Format |
|---|---|---|
GET https://pagelet.link/api/capabilities | "What can the service do right now?" — which optional features are enabled in this deployment | JSON, cache-control: no-store (never cached — it is the runtime truth) |
GET https://cdn.pagelet.link/v1/capabilities.md | "What can the runtime do?" — the authoring contract every pagelet gets from the one tag | Markdown with a YAML front-matter manifest, no-cache (revalidates) |
Docs describe design; the manifest is the runtime truth. Read the service manifest before offering anything optional — email login, claim, private artifacts, cloud PDF, SSO, billing, custom domains, notebooks. When a flag is false, the feature fails closed server-side; skip it gracefully and don't promise it.
The service manifest
curl -sS https://pagelet.link/api/capabilities
{
"schema": 1,
"service": {
"cloud_publish": true,
"url_scanning": true,
"cloud_pdf": true,
"accounts": true,
"claim": true,
"web_login": true,
"password_login": true,
"sso": { "google": false, "github": false, "microsoft": false },
"dashboard_mutations": true,
"mcp": true,
"live_dashboards": true,
"versioning": true,
"pro": false,
"private_artifacts": true,
"brand_extract": false,
"custom_domains": false,
"notebooks": true
},
"runtime": "https://cdn.pagelet.link/v1/",
"default_expiry_days": 30,
"abuse_contact": "mailto:abuse@pagelet.link"
}| Flag | Meaning when true |
|---|---|
cloud_publish | Hosted delivery is available (POST /api/upload, MCP publish_pagelet). The cloud-default delivery policy keys off this. |
url_scanning | The async URL-scanner pipeline is configured (publish + every new version is scanned). |
cloud_pdf | Browser Rendering is configured — /api/pdf, render_pdf and seals work. |
accounts | Agent registration exists (always true). |
claim | Email delivery is configured, so the claim OTP can actually be sent. Check before offering claim to a human. |
web_login | Email-OTP dashboard sign-in (needs email + session key). |
password_login | Password sign-in (needs only the session key). |
sso.{google,github,microsoft} | Per-provider social sign-in — on only when that provider's OAuth keys are set. |
dashboard_mutations | Owners can rename / re-expire / delete / set visibility from the dashboard API. |
mcp | The MCP server is up (always true). |
live_dashboards | render_dashboard / POST /api/dashboards (always true). |
versioning | Republish-in-place, ?v=N pins, /__version polling (always true). |
pro | Stripe billing is configured. |
private_artifacts | The per-artifact password gate is enabled (launch flag). |
brand_extract | Firecrawl brand-scrape → theme (extract_brand, /api/brand). |
custom_domains | Owner hostname mapping is enabled. |
notebooks | Hosted notebooks (always true). |
runtime is the runtime base URL, default_expiry_days the anonymous default (30),abuse_contact where reports go. The same JSON is served by the MCPget_capabilities tool and the pagelet://capabilities resource.
The runtime contract
The capability doc is served next to the runtime and versioned with it — agents fetch it and follow it, so the menu updates server-side with no reinstall. Its front matter is the machine-readable part:
curl -sS https://cdn.pagelet.link/v1/capabilities.md
# ---
# schema: 1
# runtime_version: "0.2.5"
# base_url: "https://cdn.pagelet.link/v1/"
# capabilities: [markdown, mermaid, math, code, charts, theme, toolbar, toc, interactive, versions]
# status: alpha
# ---
# …followed by the full authoring contract for each capability| Capability | Status | Contract in one line |
|---|---|---|
| markdown | stable | <script type="text/markdown" data-pagelet="markdown"> → rendered, sanitised prose; source kept for round-trip export. |
| mermaid | stable | ```mermaid fenced blocks or <pre class="mermaid"> → SVG with pan/zoom/fullscreen. |
| math | stable | KaTeX. $$…$$ and \[…\] display, \(…\) inline. Single-$ inline is OFF (currency collisions). |
| code | stable | Fenced language blocks → highlight.js + copy button, theme-aware. |
| charts | stable | <script type="application/json" data-pagelet="chart"> with a Chart.js config → themed responsive canvas. |
| theme | stable | data-pagelet="theme" JSON → shadcn-named CSS variables; auto/light/dark modes; pagelet:themechange event. |
| toolbar & toc | stable | Floating toolbar (theme, PDF, PNG, copy-as-Markdown, version history — draggable + collapsible); scroll-spy TOC at ≥3 headings. Off with <body data-pagelet-toolbar="off">. |
| interactive | alpha | data-pagelet-interactive → shared layout + state→preview→prompt pipeline API; wait for pagelet:interactive-ready. |
| versions | stable | Hosted pages poll same-origin /__version → refresh toast; toolbar timeline; ?v=N pins. |
Each module is lazy-loaded — a page only fetches what it uses. Versioning rule: the rolling/v1/ channel is strictly backward-compatible; immutable exact pins live at/v1.x.y/; a breaking re-architecture would ship as /v2/, so old artifacts never break.
How to feature-detect
- Before authoring — fetch
/v1/capabilities.mdfor the authoring contract (or rely on the skill, which teaches the same protocol). - Before offering a hosted feature — check the matching
service.*flag in/api/capabilities. True → proceed; false → deliver locally / skip the offer, and say why. - Before promising a link — publish, then fetch the returned URL once and confirm 200 + your HTML. Only then hand it over.
- Never cache the manifest — it's
no-storeon purpose; a stale copy advertises features that may have been switched off.
The version-metadata invariant: an artifact page can only learn about itself same-origin (/__version, /__versions, /__pdf on its own origin — the artifact CSP allows only 'self'), and those endpoints always apply the page's own gates (blocked → 451, expired → 410, private → access cookie). Service-side, versioning: true tells you the whole loop exists. Neither side ever leaks update activity across the isolation boundary.