Status · updated 2026-11-08
What is built
Every feature of dhtml, with its state, generated from one list, so every page agrees. When a feature lands, one line changes and every page follows.
Where it runs. dhtml runs on dhtml.net. The hosted beta opens in January 2027.
§ 01 · How to read it
Three states
- 43Built
- 0Built, in testing
- 1Planned
Built implemented and tested.
Built, in testing implemented, but not yet tried in the place it is meant for.
Planned on the way.
§ 02 · Features
Features
| Feature | State | Note |
|---|---|---|
| dhtml.config and secrets | Built | Strict parser; unknown keys get a "did you mean" hint; secrets only from .env or the environment. |
| File-based routing | Built | The file path is the URL; [routes] overrides; routing = explicit. |
| Security headers and request limits | Built | CSP, X-Frame-Options, nosniff, referrer policy; fixed timeouts and size limits. |
| Template engine | Built | Output is escaped for the place it lands. No raw filter exists. |
| SQLite and migrations | Built | Pure-Go driver, WAL, checksummed migrations, bound parameters only. |
| Actions, validation, CSRF, uploads | Built | Rate limits per address and per account; uploads under random names. |
| AI calls and streaming | Built | Providers: anthropic, openai-compatible, fake. Tested against local fake servers; no test calls a real provider. |
| Accounts and sessions | Built | PBKDF2-SHA256, hashed session tokens, emailed confirm and reset links, [protect] paths. |
| Outgoing mail (SMTP) | Built | STARTTLS or TLS only. The example apps use the log transport. |
| Computation: <d:set> and arithmetic filters | Built | add, sub, mul, div, round, sha256, base64, urlencode. |
| Outbound calls: [http] and <d:http> | Built | Declared hosts only, https only, no redirects, no private addresses unless declared. Gate-tested: no tag builds SQL, HTTP, a header or a body from a string; an undeclared or private address cannot be reached. |
| Signed webhooks with dedupe | Built | Stripe, GitHub and generic HMAC schemes; an event runs once. A bad, missing or old signature changes nothing (tested). |
| Stripe payments (examples/shop) | Built | Tested end to end against a local fake of Stripe only. Never run against the real service. |
| Jobs: scheduled and queued work | Built | server/jobs/, <d:job>, <d:enqueue>, retries, dhtml jobs. Reviewed; the review found a full queue could stop the worker, fixed with a test. |
| API keys, bearer tokens and CORS | Built | apikey actions, <d:newkey />, <d:revokekey />, [cors]. |
| AI as data: usage and history | Built | usage=, <d:history />, structured fields. The runtime keeps no credit balances; a per-day spending cap is not built. |
| Fast navigation (SPA-style page changes) | Built | [app] navigation = fast: links and forms swap only what changed; every page stays a plain server-rendered page and works without JavaScript. |
| Magic-link sign-in | Built | <d:magic />, one click, once; a mail scanner opening the link signs nobody in. |
| Saving pictures from services: <d:save> | Built | Refuses anything that is not the picture it claims to be; a failed action leaves no file. |
| Banning accounts and the account log | Built | A ban ends sessions and API keys at once; sign-ins, bans and resets are logged. |
| Telling the site owner by mail: <d:notify> | Built | Mails the site's owner from an action; needs [mail]. See templates.md. |
| Answers that are not HTML: <d:respond type> | Built | xml and text, always UTF-8 with nosniff. |
| Components: <d:component> and <d:props> | Built | server/components/*.dhtml. Inputs are checked at compile time and a component sees only its inputs; <d:slot /> carries the content. |
| Client state: islands (/_dhtml/state.js) | Built | data-d-state, data-d-text, -show, -class-X, -attr-X, -on-EVENT, -model, <template data-d-for>. Its own expression interpreter: no eval, works under the closed CSP, text is escaped. Checked by hand in Chromium on examples/board: first draw from server state, live add, move and remove from a second person, titles stay text (a <b> title makes no element), console clean, and the island and its live connection restart after a fast-navigation form swap. Not automated, and not tried in Firefox or Safari. |
| Live updates: <d:publish>, [channels], /_dhtml/events | Built | Server-sent events, sent only after the commit, with public, auth, admin and user rules. Limits: 5 connections per visitor, 1000 in total, and one process only. WebSocket is not built. |
| Board example (examples/board) | Built | A shared board with live updates built only from these parts, with no script of its own. |
| LaunchSaaS starter (examples/launchsaas) | Built | Credits, plans, Stripe, text and image studios, control centre, contact form and inbox, blog, docs, changelog, sitemap and feed, magic links. Reviewed and tested; Stripe and the image model have not been tried against the real services. |
| Sign in with Google: [oauth] | Built | The code flow with PKCE and a signed state cookie; only an address Google has verified signs in; an account with that address is linked, and with registration on a new one is made. Not yet proven in production. |
| Mail to the visitor: <d:mail /> | Built | A plain-text confirmation with a link the action generated, or a mail to the next person on a waitlist. Text and values come only from declared form fields and the action's own earlier steps; a visitor's value is one short line with anything a mail client would link removed; at most 3 mails to one mailbox a day and a site-wide hourly limit, counted in the database so they hold across restarts. Independently reviewed (seven findings fixed). |
| Compression and long caching | Built | Text answers are sent gzipped, and a file addressed with a version in its query (?v=) is cached for a year. |
| Guide for AI agents | Built | docs/agent-guide.md: the loop, the patterns and the common errors, short enough for an agent to read first. Written after AI agents built whole apps from it. |
| Mail to many rows: <d:mail for=> | Built | Send a reminder to every booking, or a note to everyone on a waitlist, from a job or an admin action: 1 to 100 mails a time, sent after the commit, with the same per-mailbox and hourly limits on each. |
| HTML mail with templates and a live preview | Built | Write a mail as a template in server/mails/ with a short list of safe tags; dhtml makes the text part for you, and dhtml mail preview shows the result with sample values without sending anything. |
| Reusable steps: <d:use> | Built | Write a query, a check or a guard once in server/steps/NAME.dhtml and use it from any page or action with <d:use src="NAME" />. It is checked as if written in place, and errors name the steps file. |
| request.host: many sites in one app, by name | Built | The name the visitor used, read from the Host header, so one app can serve many shops or sites and choose each by name. Pages that read it are marked Vary: Host. |
| Numbers and dates: fixed, thousands, date layouts, date and time rules | Built | fixed N and thousands for prices, date with a layout of your own, and validate date and time rules that accept only a real day and a real time. |
| Zip files as an upload type | Built | types=zip joins png, jpg, pdf, csv and the rest of the allowed list for uploads. |
| Starters: LaunchBlog, LaunchSaaS | Built | Zips of LaunchBlog, LaunchSaaS, notes and shop to download and upload to a site. Both starters have tests and READMEs. LaunchSaaS has been reviewed. LaunchBlog has not had an independent review of its current version. Neither has run in production. MIT-licensed. |
| LaunchBlog starter (examples/launchblog) | Built | A news site: masthead with date line and ticker, lead story, top stories and sections; categories; several authors with author pages; contributors who sign in and write drafts that an editor publishes; generated stock cover pictures; search-engine data on every page; and an AI writer on a schedule the editor sets, labelled as AI-written. Tested with the fake AI model only, never with a real one; no independent review of this version; never run in production. |
| Signing in actions: hmac filters | Built | |
| Following redirects: <d:http follow> | Built | |
| Languages: [lang], the t filter, mail in the recipient's language | Built | |
| Deploy by API with a deploy key | Built | |
| Hosting on dhtml.net | Planned | Hosted beta from January 2027. |
§ 04 · 1.0
The release gate
1.0.0 ships only when every line below is checked. Nothing broken ships.
- Independent security review of the hosting
- LaunchBlog and LaunchSaaS built on dhtml and running in production for two weeks
- Syntax and config frozen, with a written stability promise for 1.x
- Security review: every break test passes, plus an independent review
- A person who has never used dhtml deploys a starter using only the docs
- A way to report vulnerabilities
§ 05 · What the proof is
How "built" is decided
Every feature starts with a failing test. Every attack in the security plan is a real test with a name. After each area is built, a second reviewer reads the changes looking for security problems and for checklist items that were ticked without real proof; their findings are fixed with tests.
