put

tray put <path...>

Publish a folder, .zip, .tar.gz, .html file, any other file (a PDF, an image…), several files, or - for HTML on stdin. Prints the URL.

One file opens straight from the link. Several files, or a folder without index.html, get a page that lists them. Several files have no default name, so pass -s.

-s, --site <name> Site name. Defaults to the folder or file name.
--private Only you can see it. Applies to new sites.
--spa Unknown paths serve /index.html.
--replace Overwrite a site put from somewhere else.
tray put ./q3-review --json{  "site": "q3-review",  "url": "https://q3-review.acme.dev",  "visibility": "public",  "deploy": "lq3k2-8f1a",  "files": 42,  "uploaded": 3,  "bytes": 3145728}

list

tray listalias ls

Your sites, with visibility, domains and when they changed.

tray listSITE        URL                          VISIBILITY    DOMAINS         UPDATEDq3-review   https://q3-review.acme.dev   private (3)   —               2m agodocs        https://docs.acme.dev        public        docs.acme.com   3d ago

open

tray open <site>

Opens the site in your browser. Without a terminal, prints the URL.

edit

tray edit <site>

Change a site’s visibility. Making a site public asks first.

--visibility <v> public or private.
-y, --yes Skip the confirmation.

rollback

tray rollback <site>

Go back to the previous version, or to a specific one.

--to <deploy> Deploy id to go back to. Without it, you pick from recent ones.

remove

tray remove <site>alias rm

Take a site down, with its domains and sharing. Asks first.

-y, --yes Skip the confirmation.

share

tray share <site> [who...]

Who can see a private site. Add emails or @domain. With no one listed, prints who has access. Use tray unshare to remove.

tray share q3-review bob@acme.com @acme.comtray unshare q3-review bob@acme.com

domain

tray domain

Custom domains. The domain must be on the same Cloudflare account. Your tray uses the Cloudflare token tray setup saved; run setup again to change it.

add <host> -s <site> Point a domain at a site.
remove <host> Remove it. Alias rm.
list [-s <site>] List domains. Alias ls.

login

tray login [domain]

Log this machine in to a tray. Opens your browser, or prints a code to approve somewhere else.

approve <code> Approve a login from a machine that’s logged in.
logout [domain] Log out.
account list Trays you’re logged in to.
account switch <d> Change the default tray.

key

tray key

API keys for agents and CI. Use one with TRAY_API_KEY.

create [--name <n>] Print a new key. It’s shown once.
list Your keys.
revoke <name> Turn a key off.

setup

tray setup

Create or update your tray on Cloudflare. Safe to run again. tray upgrade updates the CLI.

Without CLOUDFLARE_API_TOKEN, setup prints a link that pre-fills a token with everything it needs, opens it, and asks you to paste the token. It also needs Cloudflare Zero Trust turned on (the Free plan is enough).

--domain <d> Domain on your Cloudflare account.
--email <e> Your email, for logging in.

Global flags

--json Print one JSON object. Implies --non-interactive.
--non-interactive Never prompt. Missing input is an error.
-y, --yes Accept confirmations.
--domain <d> Use this tray instead of the default.
-h, --help Help for any command.
-v, --version Print the version.

Environment

TRAY_DOMAIN Tray to use.
TRAY_API_KEY API key. Overrides your login.
CLOUDFLARE_API_TOKEN Used by setup and upgrade.
CI Set: never prompt.
AGENT, AI_AGENT Set: an agent is running. Never prompt.
TRAY_INTERACTIVE 1: prompt anyway, even under an agent.
NO_COLOR Set: no colors.

Exit codes

0 Done.
1 Something failed: network, server or a conflict.
2 Bad usage or missing input.
4 Not logged in, or not allowed.
130 Cancelled: Ctrl-C, or no at a prompt.

With --json, errors are JSON too:

{  "error": "q3-review already exists",  "code": "site_exists",  "hint": "use --replace or -s <other>"}