Concepts
How 9d9 works: static deploys, claiming, forms and analytics.
9d9 hosts static sites. Sites are built and changed by AI — every change, from a typo to a redesign, is a new build pushed as a deploy. There is no CMS: the deployed folder is the site.
Static hosting
Every deploy is an atomic snapshot of a dist/ directory.
Files live in R2 under a deploy_id prefix. A small KV entry
per hostname points at the current deploy_id. When you
activate a deploy we flip that pointer; old files stay around for a week
so rollback is one tool call.
Request path
- Browser hits
your-slug.9d9.dev/about. - Render Worker reads
host:your-slug.9d9.devfrom KV — gets{org_id, current_deploy_id}. - Tries R2 keys in order:
about/index.html,about.html, thenabout. - First hit is served. If none, returns the deploy's
404.html(or a generic).
Cache headers
| File class | cache-control |
|---|---|
HTML (*.html, /) | public, max-age=0, must-revalidate + ETag |
Hashed (/_astro/, /_next/static/, *.HASH.*) | public, max-age=31536000, immutable |
| Everything else | public, max-age=300, stale-while-revalidate=86400 |
Claiming
An AI can create a site and deploy to it before anyone has an account
(POST /v1/sites, or the CLI with no key). Nothing is public
yet: slug.9d9.dev shows "Not published yet". The response
includes a claim link; the owner opens it, confirms with their email, and
the site goes live as theirs. Unclaimed sites are deleted after 7 days.
The key the AI received keeps working after the claim — until then it can only deploy; afterwards it can also read contacts, attach domains and upload media.
Each network can create one site a day without an account and own up to ten. Signed in, you skip the claim step entirely: create a site in the dashboard and give your AI a key from its Settings page. Schools, agencies and shared offices can ask for more at app.9d9.dev/limits.
Forms
Point any form at the contacts endpoint. Submissions appear under Contacts in the dashboard.
<form action="https://api.9d9.dev/contacts/{org_id}/submit" method="POST">
<input name="name"> <input name="email" type="email"> <textarea name="message"></textarea>
<input type="hidden" name="_source" value="contact-form">
<input type="hidden" name="_redirect" value="https://your-site/thanks/">
<input name="_honeypot" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px">
</form>
It accepts form posts and JSON fetch() from any origin.
_honeypot must stay empty (bot trap); _redirect
sends plain-HTML submits somewhere after success.
Analytics
First-party, cookie-light pageviews. Add to every page's <head>:
<script src="https://api.9d9.dev/beacon" data-org="{org_id}" async></script>