html-docs · product plan · awaiting go-ahead

HTML Docs as the place projects keep their brain

A four-phase plan to evolve HTML Docs from single published pages into the default way developers host documentation — internal project wikis an agent keeps current, and public docs sites — built almost entirely on primitives the product already has.

Status plan approved in principle, implementation not started · Date Jul 4, 2026 · Grounding every claim verified against the codebase

01Why this, why now

HTML Docs already has the hard parts of a documentation platform: instant CLI/agent publishing, collaborative region-based editing, comments with AI answers, and folders with cascading permissions. What it lacks is exactly three things — and all three are additive, not rewrites:

GapToday
No multi-page sitesEvery published page is standalone. Folders group docs for permissions, not navigation. "Tabs" exist in the editor but only the root tab publishes.
No searchZero server-side full-text search. The dashboard filters titles client-side; the chat source picker does a title-only ilike.
No repo bridgeNo way to sync a repo's /docs markdown into a living site. The API already accepts markdown — but one doc per request, no manifest, no idempotence.

The differentiator against Notion/Confluence (internal) and Mintlify/GitBook (external) is the agent surface that already exists: hdk_ API keys with per-agent attribution, an MCP server, a published skill, and account-level webhooks. Nobody else's docs product treats the agent as a first-class maintainer.

Decisions locked
  1. One "sites" primitive serves both wedges — internal wiki and public docs site are the same thing with different access settings.
  2. App-canonical + repo sync — HTML Docs is the source of truth; markdown syncs in from repos via CLI/CI (one-way; two-way deferred).
  3. Knowledge layer v1 = search + "ask this wiki" — full-text search and grounded AI answers first; wikilinks/backlinks/graph later.

02The core idea: a site is a published folder

Folders already have everything a wiki needs for structure and access: nesting (25 deep), collaborator roles (viewer → admin), cascading permissions, visibility, share codes. So we don't invent a new container — we add a thin sites table that points at a folder and owns only the publishing concerns: the URL slug, theme, index page, and (later) a custom domain. Pages are ordinary documents inside the folder, each gaining a page slug and a position.

sites (new, thin) slug · access · theme index page · published_at custom domain (later) folder tree (existing) ▸ docs/ ▸ Guides/ = nav section • getting-started (page) • deploy (page) ▸ API/ … 1 : 1 permissions: unchanged roles + cascade already live in folder-access.ts zero new permission code /site/acme-docs/deploy catch-all route render page HTML getRenderedHtml (existing) inject site chrome nav · search · prev/next same seam OG tags use today
Fig. 1 — Blue marks what's new. The folder tree, permissions, and page-rendering pipeline are untouched; the chrome injection reuses the exact string-injection seam that already adds OG tags and the view tracker to every published page.

Internal wiki vs public docs site is one switch: a private site runs a folder-role check in the serving route (session cookies are already available there) and responds with no-store cache headers; a public site keeps today's CDN caching and gets indexed.

03The four phases

1 · Sites primitivefolder → published multi-page site with naveffort L
2 · Repo syncmd → site via CLI/CI, agents maintaineffort M
3 · Knowledgefull-text search + ask-this-wikieffort M/L
4 · Growthdomains · SEO · teams · importseffort L, parallel tracks

Each phase ships independently and is useful on its own.

Phase 1 — Sites primitive

ships the producteffort L

Everything needed to publish a folder as a navigable site at /site/<site>/<page>.

Phase 2 — Repo sync & agent maintenance

the wedgeeffort M

The "second brain that stays current" story: a repo's /docs folder becomes a site, and agents keep it alive.

repo /docs/*.md front-matter: slug · order cli sync / CI action hash-based, idempotent site pages versions snapshotted webhook in-app edits notify unchanged files skip · removed files archive (never CI-delete) · ~50 pages per call, chunked
Fig. 2 — One-way sync in; one-way notify out. When someone edits a synced page in the app, the repo owner's webhook fires with the source path so a bot can open an issue or PR.

Phase 3 — Knowledge layer v1

the braineffort M/L

Phase 4 — Growth & monetization

effort L · independent tracks
TrackApproach
Custom domains firstHost routing in middleware rewrites docs.acme.com/* to the site; Vercel Domains API + TXT verification from a settings panel. Business plan.
SEOPer-site sitemap.xml + robots.txt from the same route; private sites are already noindex from Phase 1.
Teams / seatsReal org model is its own initiative. Interim: folder collaborators already give per-site teams; price by sites/pages, defer seats.
Versioned docsDefer — sync already snapshots every version, so "view page as of vX" is a cheap read-only render later.
Import funnelsNotion / Confluence / GitBook exports are zips of md+html — they funnel through the Phase-2 sync endpoint as guided flows.

04Validate these three things before writing Phase-1 code

RiskHow we de-risk it
Chrome injection vs arbitrary user HTMLPublished pages are arbitrary HTML — full-viewport dashboards, flex bodies, fixed headers. Prototype the shadow-DOM sidebar against 15–20 real production pages before committing. Fallback: iframe shell (worse for SEO).
Private wikis on a CDNOne wrong cache header leaks a private wiki to strangers. Verify on a Vercel preview that sessions are readable in the serving route and that no-store responses never hit the edge cache.
FTS backfill at scaleAdding a generated column rewrites every region row. Dry-run the migration on a staging copy with real row counts; fallback is a trigger-maintained column with identical query shape.

05How we'll know each phase works