OpenTree DashboardSign in

$ npx wrangler deploy

Run the whole thing in your own account

Self-hosting is not a tier here, it is the only way it runs. Clone the source, create the storage, deploy to Cloudflare — after which every page, every record and every byte lives in an account you control.

What you need

Get the source

git clone https://github.com/yao00oo/opentree
cd opentree && npm install

Create the storage

npx wrangler d1 create opentree
npx wrangler r2 bucket create opentree-content
npx wrangler d1 migrations apply opentree --remote

Put 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 email

Deploy

npx wrangler deploy

That 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.html

Then 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 site

They 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 --local

D1 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

That is the trade. Nobody can read your content, and nobody is on call for it either.

Defaults you inherit

DefaultWhat it means
VisibilityUnlisted. The URL carries a 22-character random token; nothing is listed publicly.
Expiry7 days for a keyed publish, 24 hours for an anonymous one. Pass never to keep it.
After expiryThe row and the stored object are both deleted by a scheduled purge, not just hidden.
RobotsX-Robots-Tag: noai, noimageai, noindex on every viewer response.
ReferrersReferrer-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.

Keep reading