Open Artifacts

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 enable provides 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 example artifacts-content.example.com).

Steps

  1. Check the prerequisites. Run node --version, pnpm --version, and git --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.

  2. Clone the latest release. Open Artifacts installs from the latest stable GitHub release, not main and not a pre-release. Release tags look like vX.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-artifacts

    If TAG comes back empty or curl fails, stop and tell the user: “Open Artifacts has no stable release yet; check back later.”

  3. Install dependencies: pnpm install.

  4. Ask the user to log in to Cloudflare. Ask them to run npx wrangler login and approve access in the browser. On a remote machine or in a container, use npx wrangler login --device instead. This is the one step a person has to do.

  5. 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

    -s keeps 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"}, where status is ok, skipped, action_required, or error. It stops at the first action_required or error. Then go by the exit code:

    • 0: every step is done. Go on to step 6.
    • 2: the last line is action_required. If its message asks you to pass a flag, such as --account-id when 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 the message to the user verbatim, with data.url if it has one, wait until they say it’s done, and run the same command again. Setup saves its progress in .openartifacts/state.json and picks up where it stopped.
    • 1: the last line is error. Show the user its message and stop.

    If the access step asks for an Access API token, the user creates one at its data.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_TOKEN

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

  6. Connect yourself. The owner-token line’s data.token is the owner’s personal access token (oa_pat_…). It’s shown only once, by the run that mints it, so keep it. The agent-config line’s data.url is the MCP URL, and its data.snippets holds MCP configs for claudeCode, codex, cursor, opencode, and a generic json. They don’t contain the token: most read it from the OA_TOKEN environment variable, and json has 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 as OA_TOKEN to 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.

  7. Open the Welcome page. Setup publishes a Welcome artifact to test the connection. Give the user its link, data.welcomeUrl on the selftest and agent-config lines, so they can sign in and see it. Only a run that mints the owner token publishes it; if there’s no welcomeUrl, give the user https://<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:

  1. prereqs: checks Node 22 or later, pnpm, the Cloudflare login and account, and that both hostnames are in a zone on that account.
  2. resources: creates or reuses the D1 database, the R2 bucket, and the KV namespace, and writes apps/server/wrangler.jsonc.
  3. access: creates the Cloudflare Access for SaaS application and its sign-in policy.
  4. secrets: stores the Worker secrets. Without --json or --yes, it also offers to store the optional ANALYTICS_TOKEN for the Usage page.
  5. deploy: builds the server, applies database migrations, and deploys the Worker.
  6. owner-token: mints a personal access token for the owner, unless setup already minted one that’s still valid.
  7. selftest: checks /healthz and 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.
  8. 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.