How-to

Take an org live

From an empty account to a site on your own domain, with data, scripts and AI agents writing safely, and a way back if something goes wrong. Each step links to the detailed guide.

1. Org and slug

Every account is an org. Sign up in the Admin UI, then give the org a readable slug before you share any URL. Public URLs and custom domains contain the slug, and changing it later breaks them.

http · org owner
PUT /api/v1/org/slug
{"slug": "tkd-tracker"}          # 3–40 chars: lowercase letters, digits, hyphens

More: Find your org slug and build public URLs.

2. People and keys

  • People: invite collaborators with POST /api/v1/invites {"email": "…", "role": "member"} (or "admin").
  • One API key per script, CI job and agent (Admin UI → API Keys, or wren keys create). Store keys as secrets, never in code or page source. A key always acts in the org it was created in.
  • Least privilege: keys created by the org owner bypass all permission rules. For a restricted writer, create the key from a member account and give it key:<keyId> rules, for example write access to one collection only.
  • CLI: export WREN_URL=… WREN_API_KEY=wren_…. Keys don't expire mid-run the way login sessions do.

3. Data model

As an admin, once per collection: declare a JSON Schema and a natural key, so every writer can upsert with PUT …/by-key/{key} and re-runs never create duplicates. Use ISO dates (2026-10-04) so where filters work.

http · admin
PUT /api/v1/events/_schema
{"naturalKey": "slug", "schema": {"type": "object", "required": ["slug", "name", "date"]}}

More: Update data and files without duplicates. For numbers you recompute after every write (standings, totals), add a materialized query.

4. Decide what's public

Nothing is public until you add a principal: "*" read rule. Decide per tree and collection:

WhatPublic ruleWhy
The site (tree){"resource":"tree:mysite","labelFilter":"published"}Visitors see released pages only; deploys stay private until promote
Live data (scores, feeds){"resource":"collection:results"}, no label filterVisible the moment it's written
Curated data (articles){"resource":"collection:articles","labelFilter":"published"}Released together with the site
Personal or internal datanoneStays private; read it with a key

Public means discoverable. Everything a * rule allows is listed at /api/v1/projects and in /orgs/{slug}/llms.txt, including sample documents. Read both before launch.

5. First release

bash
wren deploy ./dist --tree mysite --label preview --public   # creates the published-only rule
curl -H "Authorization: Bearer $WREN_API_KEY" "$WREN_URL/api/v1/tree/mysite/index.html?label=preview"
wren promote mysite --from preview --label release-1        # name the release, for rollback
wren promote mysite --from preview                          # go live, in one transaction

More: Publish a site and keep drafts private and Deploy, preview, promote.

6. Your domain

A small Cloudflare Worker maps your domain onto the public tree. It needs no API key, and it also gives the domain its own MCP endpoint:

toml · wrangler.toml [vars]
UPSTREAM = "https://wren.aemwip.com/orgs/tkd-tracker/tree/mysite"
MCP      = "https://wren.aemwip.com/orgs/tkd-tracker/mcp?tree=mysite"

More: Serve a site on your own domain.

7. AI agents

  • Your own agents connect to https://<wren-host>/mcp with their own key. They write to preview by default, and you promote.
  • Visitors' agents use https://your-domain/mcp: public, read-only, and limited to the site that domain shows (?tree=). Other trees and collections stay invisible. A key from another org is refused.
  • Give agents that only answer questions /mcp?readonly=1.

More: Connect AI agents with MCP.

8. Edge settings (Cloudflare in front of WREN)

  • Scripts get 403 error code: 1010? Turn off Browser Integrity Check for the WREN hostname (Configuration Rule), and add a WAF skip rule if Bot Fight Mode is on. See Use WREN from Python.
  • Caching: WREN sends max-age=60 on public reads and no-store on errors and on everything authenticated. Make sure no Cache Rule or Browser Cache TTL overrides that with hours.
  • HTTPS only: share https:// URLs; plain http:// redirects.

9. Email, backups and upgrades (self-hosted)

  • Email: set SMTP_URL and MAIL_FROM so sign-ups get a confirmation email, password resets work, and invites are delivered. Without them nothing is sent: links are written to the server log, and invite responses include the link to share yourself. Set BETTER_AUTH_URL to your public https:// address so the links point there. Once delivery works, you can require confirmation with REQUIRE_EMAIL_VERIFICATION=true.
  • Back up Postgres daily with pg_dump -Fc. Every org lives in its own schema in that one database, and file contents are stored in it too, so one dump is the whole instance. Keep a week of daily dumps plus monthly ones, and keep a copy off the machine.
  • Prove the backup restores: restore into a throwaway Postgres container regularly and compare table counts. A 2.4 GB dump restores in about 4–5 minutes on a desktop machine.
  • Upgrades: pin the image tag, take a backup, then pull and restart. Database migrations run automatically at startup (look for applying vN in the log). Check /health afterwards.

Launch checklist

  • ☐ Slug set and final
  • ☐ One key per script, CI job and agent, stored as secrets; no keys in page source or git
  • ☐ Schemas and natural keys declared for collections that scripts write
  • ☐ Public rules reviewed: site with labelFilter: "published"; live data deliberately without; nothing personal public
  • ☐ /orgs/{slug}/llms.txt and /api/v1/projects read through: nothing there you don't want public
  • ☐ First release promoted, and a named release label exists for rollback
  • ☐ Domain serves /, deep links and assets; a missing page returns 404
  • ☐ https://your-domain/mcp without a key shows only this site
  • ☐ Edge: no 1010 for your scripts; no long cache overrides
  • ☐ Email delivery configured (SMTP_URL, MAIL_FROM, BETTER_AUTH_URL); a test sign-up receives its confirmation
  • ☐ Backups scheduled, one restore tested

After launch

  • Roll back: wren promote mysite --from release-1. It's one transaction, and nothing is lost.
  • Rotate a key: create the new one, switch the script over, then revoke the old one (wren keys revoke).
  • See what changed: every write is a version, so …/versions and …/diff show what a script or an agent did.