What you need
- A Cloudflare account. The free plan is enough to start.
- Node and
npxlocally. - A domain, if you want one — the deployment answers on a workers subdomain otherwise.
- Optionally a GitHub OAuth app and a Resend key, for browser sign-in and the digest email.
Get the source
git clone https://github.com/yao00oo/opentree
cd opentree && npm installCreate the storage
npx wrangler d1 create opentree
npx wrangler r2 bucket create opentree-content
npx wrangler d1 migrations apply opentree --remotePut the returned ids into wrangler.toml. That file is also where the limits live:
upload ceiling, default expiry, rate-limit window.
Set the secrets
npx wrangler secret put JWT_SECRET
npx wrangler secret put GITHUB_CLIENT_SECRET # optional, for browser sign-in
npx wrangler secret put RESEND_API_KEY # optional, for emailDeploy
npx wrangler deployThat is the setup. The MCP server, the REST API, the dashboard and this entire site are one Worker.
Check it
curl -s https://your-deployment/health | jq .
curl -X POST https://your-deployment/v1/publish -F file=@index.htmlThen open the returned link in a browser and look at it. A 201 is not evidence
that the page renders — that habit is worth adopting from the first deploy.
Run the test scripts
bash qa/upto.sh 6 # every phase, in order
bash qa/live.sh # against the deployed origin
bash qa/sitewalk.sh # every page of the siteThey are the same gates the build passes. If they pass against your deployment, your install behaves like the reference one.
Rebrand it
Every product name, domain, key prefix and MCP server name comes from one config file. Change it and the entire surface follows — pages, headers, tool names, the dashboard:
{
"name": "yourname",
"displayName": "YourName",
"primaryDomain": "pages.yourcompany.com",
"apiKeyPrefix": "yn_live_",
"mcpServerName": "yourname"
}Local development
npx wrangler dev --localD1 and R2 are simulated locally, so the tests run without a Cloudflare account at all.
Point a domain at it
A route in wrangler.toml for the deployment's own hostname, and the
custom domains flow for the per-page hostnames your clients see.
Access and audit
API keys are hashed, OAuth tokens are signed and revocable, and the browser session is never
accepted as API credentials. Every one of those decisions is in code you can read — the audit is
git log, not a certificate.
Updates
Pull and deploy. Migrations are files in the repository; apply them and redeploy. Nothing updates itself underneath you, which cuts both ways — see the changelog for what changed.
Running it for a team
One deployment, keys per person or per agent, revocable individually. There are no seats to buy and no workspace object to manage.
What it costs to run
Cloudflare's free allowances cover the workloads this was built for. Beyond them you pay their normal rates and nothing else — the arithmetic.
What you are taking on
- Your own uptime, your own backups, your own key rotation.
- Whatever your users publish, and any abuse handling that comes with it.
- Deciding when to update.
Defaults you inherit
| Default | What it means |
|---|---|
| Visibility | Unlisted. The URL carries a 22-character random token; nothing is listed publicly. |
| Expiry | 7 days for a keyed publish, 24 hours for an anonymous one. Pass never to keep it. |
| After expiry | The row and the stored object are both deleted by a scheduled purge, not just hidden. |
| Robots | X-Robots-Tag: noai, noimageai, noindex on every viewer response. |
| Referrers | Referrer-Policy: no-referrer, so the token never leaks into someone else's logs. |
Questions
Is the source complete?
Yes — what runs here is what is in the repository.
Can I modify it?
It is your deployment. Check the licence in the repository for what you may redistribute.
Do I have to self-host?
There is no hosted alternative to compare against. This is it.