Set up Open Artifacts
Deploy your own instance to Cloudflare. Your agent does every step except the Cloudflare login.
Open Artifacts runs on your own Cloudflare account and domain. The easiest way to install it is to tell your coding agent:
Set up open-artifacts.com/llms.txt
The agent follows the steps below. The only thing you do yourself is approve the Cloudflare login in your browser.
What you need
- Node.js 22 or later, with pnpm (
corepack enableprovides it). - git.
- A Cloudflare account. The free plan is enough.
- A domain on Cloudflare. Open Artifacts uses two hostnames on it: one for the app (for example
artifacts.example.com) and one for artifact content (for exampleartifacts-content.example.com).
Steps
-
Check the prerequisites. Run
node --version,pnpm --version, andgit --version. If anything is missing, or the user has no Cloudflare account or no domain on Cloudflare, explain what it is and how to get it, then wait. -
Clone the latest release. Open Artifacts installs from the latest stable GitHub release, not
mainand not a pre-release. Release tags look likevX.Y.Z:REPO=https://github.com/leourbina/open-artifacts TAG=$(curl -fsSL https://api.github.com/repos/leourbina/open-artifacts/releases/latest | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p') git clone --depth 1 --branch "$TAG" "$REPO" open-artifacts cd open-artifactsIf
TAGcomes back empty orcurlfails, stop and tell the user: “Open Artifacts has no stable release yet; check back later.” -
Install dependencies:
pnpm install. -
Ask the user to log in to Cloudflare. Ask them to run
npx wrangler loginand approve access in the browser. On a remote machine or in a container, usenpx wrangler login --deviceinstead. This is the one step a person has to do. -
Run setup. Use the user’s hostnames and email:
pnpm -s oa:setup --json --app-host artifacts.example.com --content-host artifacts-content.example.com --owner-email you@example.com --name open-artifacts-skeeps pnpm’s own output off stdout, so every line is JSON. With--json, setup never prompts. Setup prints one JSON object per line,{"step", "status", "message", "data"}, wherestatusisok,skipped,action_required, orerror. It stops at the firstaction_requiredorerror. Then go by the exit code:- 0: every step is done. Go on to step 6.
- 2: the last line is
action_required. If itsmessageasks you to pass a flag, such as--account-idwhen the login can reach several accounts, add that flag and run again; ask the user for the value if you don’t know it. Otherwise relay themessageto the user verbatim, withdata.urlif it has one, wait until they say it’s done, and run the same command again. Setup saves its progress in.openartifacts/state.jsonand picks up where it stopped. - 1: the last line is
error. Show the user itsmessageand stop.
If the
accessstep asks for an Access API token, the user creates one at itsdata.url. Ask them to run this in the terminal where setup runs and paste the token, which isn’t shown or saved in shell history:read -rs OA_ACCESS_TOKEN; export OA_ACCESS_TOKENThen run the same command again. Never put the token on a command line, where shell history keeps it. Setup never saves it. Once Access is set up, runs without the token skip re-checking Access, as long as the app host and Cloudflare account stay the same. The token is needed again only to change the app host or account, or to re-check Access.
-
Connect yourself. The
owner-tokenline’sdata.tokenis the owner’s personal access token (oa_pat_…). It’s shown only once, by the run that mints it, so keep it. Theagent-configline’sdata.urlis the MCP URL, and itsdata.snippetsholds MCP configs forclaudeCode,codex,cursor,opencode, and a genericjson. They don’t contain the token: most read it from theOA_TOKENenvironment variable, andjsonhas a<YOUR_TOKEN>placeholder to replace, in a file kept out of git. Add the one for this agent to your MCP config, and make the token available asOA_TOKENto its client. If you’ve lost the token, run setup again with--new-owner-token, which mints a new one and revokes the old one. Connect agents shows each client’s config format. -
Open the Welcome page. Setup publishes a Welcome artifact to test the connection. Give the user its link,
data.welcomeUrlon theselftestandagent-configlines, so they can sign in and see it. Only a run that mints the owner token publishes it; if there’s nowelcomeUrl, give the userhttps://<app-host>/instead.
Setup flags
Setup takes each value from its flag first, then from .openartifacts/state.json (saved by an earlier run), then by asking, unless --json or --yes is set. After the first run, the hostnames and email can be left out.
| Flag | Meaning |
|---|---|
--name |
Name of the Worker, its resources, and the Access app. It’s also the server name in the MCP snippets. Without saved state, it’s required with --json, --yes, --upgrade, or --check; only an interactive run defaults it to open-artifacts. |
--app-host |
The app hostname, for example artifacts.example.com. |
--content-host |
The artifact content hostname, for example artifacts-content.example.com. |
--owner-email |
The owner’s email. That person becomes the owner and gets the owner token. |
--account-id |
The Cloudflare account to use. Defaults to CLOUDFLARE_ACCOUNT_ID, or the only account the login can reach. |
--yes |
Never prompt. Missing values are errors, and the optional ANALYTICS_TOKEN is skipped. Optional with --json. |
--upgrade |
Upgrade an existing install: only deploy and selftest do work. See Upgrade. |
--new-owner-token |
Mint a new owner token, and revoke the one setup minted before. |
--check |
Read-only. Runs each step’s check without doing the work, and reports it as done or todo. Without saved state, it rebuilds the state from Cloudflare by --name and reports it on a last state line. It changes nothing on Cloudflare and writes no files. |
--strict |
Only with --check: exit 2 when any step is todo, for example to gate CI. |
--json |
Print one JSON object per line instead of text, and never prompt: a missing value is an action_required line naming the flag to pass. The optional ANALYTICS_TOKEN is skipped. |
--ci |
CI mode: implies --json; the owner token is used only for selftest, never printed, and revoked at the end of the run (also on SIGTERM or SIGINT). Requires --name; not with --new-owner-token. It keeps no state.json, so it reuses the welcome artifact by title instead of tracking its id. A SIGKILL or out-of-memory kill can leave a setup-ci token live; it is never printed. Find it by the label setup-ci in Settings → Tokens. The next --ci run revokes it before minting, or run --ci --revoke-ci-tokens as an if: always() cleanup step. |
--revoke-ci-tokens |
Only with --ci: revoke every live setup-ci token of the owner and exit. Needs --name and the owner email, not the hosts. |
--no-browser |
Omit the BROWSER binding (Browser Run, used for server-side thumbnails). Default is on and free-plan safe: Cloudflare caps Free usage (10 browser-minutes/day) and does not bill it, and no extra token permission is needed. The choice is saved in state.json, so --upgrade keeps it; stateless runs (--ci) must repeat the flag. --check and --json report browser: true or false. |
--help |
Print usage and exit (-h also works). |
| Environment variable | Meaning |
|---|---|
OA_ACCESS_TOKEN |
A Cloudflare API token for Access, needed on the first run when the wrangler login token can’t manage Access, and again to change the app host or account. |
CLOUDFLARE_ACCOUNT_ID |
The default for --account-id. |
OA_TEAM_DOMAIN |
The Zero Trust team domain (<team>.cloudflareaccess.com), used when rebuilding state if the token can’t read the Access organization. Setup verifies it before use. |
Exit codes: 0 when every step is done, 2 when a step needs the user or a missing flag (action_required), and 1 on an error. With --check, 0 means the checks ran; --strict makes a todo step exit 2.
What setup does
oa:setup is idempotent: each step checks first and skips work that’s already done. The steps, in order:
prereqs: checks Node 22 or later, pnpm, the Cloudflare login and account, and that both hostnames are in a zone on that account.resources: creates or reuses the D1 database, the R2 bucket, and the KV namespace, and writesapps/server/wrangler.jsonc.access: creates the Cloudflare Access for SaaS application and its sign-in policy.secrets: stores the Worker secrets. Without--jsonor--yes, it also offers to store the optionalANALYTICS_TOKENfor the Usage page.deploy: builds the server, applies database migrations, and deploys the Worker.owner-token: mints a personal access token for the owner, unless setup already minted one that’s still valid.selftest: checks/healthzand the OIDC discovery document. When this run minted a token, it also publishes the Welcome artifact over MCP and checks that its content is served.agent-config: prints the MCP URL and config snippets.
Cloudflare Access permissions
The token from wrangler login may not be able to manage Zero Trust (Access). If it can’t, the access step asks for an API token with Access: Apps and Policies Edit, Access: Organizations Read, and Zone: DNS Read, and links to a pre-filled form for creating one. Set it as OA_ACCESS_TOKEN; in an interactive run, you can paste it at the prompt instead. Setup doesn’t keep it. Later runs skip re-checking Access without it, unless the app host or account changes. If the account has no Zero Trust organization yet, setup links to the Zero Trust dashboard to turn it on. Zero Trust’s free plan is enough.