Front door — invite-only qren.ai
In short
Section titled “In short”qren.ai is now one calm page: the name, one line saying what Qren is, and a short form asking for an invite. It sells nothing and creates nothing — sending the form files a note in a queue Hisham reads by hand, and nobody gets an account or access by filling it in. It is the first of the five admission steps settled on 2026-08-20; the four that follow are people and other systems, not this page. Built to be replaced: when the approval queue exists, it reads from the same store.
What it does
Section titled “What it does”- Serves one static page at
qren.ai— wordmark, one line, one form. Light and dark are both first-class and follow the reader’s system setting. No analytics, no cookies, no external request, no build step. - Accepts
POST /api/invite(JSON or form-encoded) and files the request in KV for a human to read. - Succeeds with the same sentence every time: “Thank you. Invitations are personal and approved by hand; we’ll write to you.” Without JavaScript the form posts normally and gets a plain page carrying the same words.
What it does not do
Section titled “What it does not do”No self-serve signup — filling the form grants nothing. No account created, no email sent, no Access policy touched. No marketing: no pricing, no feature list, no screenshots, no newsletter. It never echoes what was typed — every response is a fixed string. It notifies nobody; the queue is read, not pushed.
The request record
Section titled “The request record”Stored in the KV namespace bound as INVITES, one key per request:
- Key —
req:<ISO timestamp>:<uuid>, so a plain key listing is already in the order the requests arrived. - Value — JSON:
email(required, lowercased),name,company,note(“what would you hand to an agent first?”),ts,ua,country. Optional fields are stored empty, never omitted. Fields are trimmed, stripped of control characters, and capped (email 254, name and company 120, note 500).
Two things guard it: a honeypot field a person never sees — filled means
the record is silently dropped and the sender is told nothing — and a
counter at rl:<hashed ip>, five an hour, expiring on its own. The address
is hashed, never stored. If the INVITES binding is missing the endpoint
answers 503 and logs it; it never pretends a request was filed.
The admission steps this feeds
Section titled “The admission steps this feeds”1. Request — this page, into INVITES. → 2. Approve — Hisham, by
hand: read the queue, add the email to the Cloudflare Access policy (see
context/infra.md). → 3. Join the network — portal identity, door and
tunnel. → 4. Grant on their machine — app install, permissions,
engagement credential. → 5. Live. Only step 1 is built; the rest stay
manual until the approval queue and the portal cover them.
Open questions
Section titled “Open questions”- Reading and approving. The queue has no interface — approving means listing KV by hand. It should become an early client of the shared approval queue, with approve and decline writing a status back onto the same record. Until then, who lists it, and how often?
- Telling the operator. A request should reach Telegram through the bridge — but that crosses into AOS while AOS is being frozen. Last thing AOS gains, or first thing Qren’s notifications ship?
- Spam. A honeypot and an hourly counter stop casual bots, not a determined one. Turnstile is the obvious next step, at the cost of a third-party script on a page that makes no external request today.
- Retention. Nothing expires a declined or stale request.