The Bailey CLI
bailey is an optional command-line companion to the dashboard. It publishes folders to a
live URL, lists your sites, reads collected submissions, runs erasure requests, and can run
a local sandbox with real storage before you ship.
Install
Section titled “Install”macOS / Linux
Section titled “macOS / Linux”curl -fsSL https://dl.trybailey.app/install.sh | shThe installer detects your OS and CPU, downloads the right binary, verifies its SHA-256
checksum, and drops it in ~/.local/bin. If that folder isn’t on your PATH, the script
tells you the line to add.
Windows (PowerShell)
Section titled “Windows (PowerShell)”iwr -useb https://dl.trybailey.app/install.ps1 | iexSame idea: it verifies the checksum, installs to %LOCALAPPDATA%\Bailey\bin, and adds that
folder to your user PATH. Open a new terminal afterwards.
Check it worked:
bailey versionbailey helpAuthenticate
Section titled “Authenticate”There are two ways to sign in, depending on who’s running the command.
You, in a terminal
Section titled “You, in a terminal”bailey loginThis opens your browser to sign in (the same login as the dashboard), then stores your
credentials locally in ~/.config/bailey/credentials.json (0600). No token to copy or
paste. Run bailey logout to clear them.
CI, with a deploy token
Section titled “CI, with a deploy token”A CI runner can’t open a browser. Instead, mint a deploy token from the dashboard
(Account → Deploy tokens), choose its scope (your whole profile, or specific sites), and
hand it to the CLI through the BAILEY_TOKEN environment variable:
export BAILEY_TOKEN=blt_…bailey deploy ./dist --app my-siteA deploy token can only do what its abilities allow — publish (bailey deploy) and/or
pull files (bailey pull), never read collected data, erase, or change account
settings — and is revocable and audited. Keep it in your CI’s secret store, not in
your repo.
Commands
Section titled “Commands”bailey deploy: publish a folder
Section titled “bailey deploy: publish a folder”bailey deploy [dir] [--app <label>] [--org <org>] [--spa] [--public <bucket>]… [--collect <bucket>]…Publishes <dir> as a new version of the site <label> and prints the live URL. If the
site doesn’t exist yet, it’s created for you. In a linked folder (see bailey link
below), a plain bailey deploy is enough — no flags to retype.
Naming a folder publishes that folder, and its link is the one read there. Naming none
lets the link of the current folder decide: its dir if it has one (a repo whose site is
built into build/), the current folder otherwise. Whatever you type wins, one dimension at
a time — a typed folder isn’t overridden by the link’s dir, a typed --app isn’t
overridden by the link’s app.
--app <label>: the site’s address label (validated; reserved labels are rejected).--spa: single-page app. A page visit that matches no file falls back toindex.html(200), so reloading/aboutworks. Missing assets still return 404. Off by default: a static site keeps honest “not found”s.--spa=falseturns it back off; omitting the flag changes nothing (the site keeps whatever it had). Equivalent to"spa": trueinbailey.manifest.json. See Apps that reload to a “Page not found”.--public <bucket>: declare a public key-value bucket (readable and writable from the page). Repeatable.--collect <bucket>: declare an insert-only collection bucket (write-only from the page). Repeatable.
Each deploy is a new version (atomic swap) and amends the site’s manifest; it never wipes your existing buckets.
bailey deploy ./dist --app my-site --collect contact --collect signups --public votesbailey link: remember where a folder publishes
Section titled “bailey link: remember where a folder publishes”bailey link <app> [dir] [--org <org>] [--dir <folder>]Links a folder to a site by writing a small .bailey.json next to your files (and adding
it to the folder’s .gitignore — the link is about your machine, it never belongs in
the repo and is never published). Once linked, a plain bailey deploy publishes the folder
— app and organization included. Run bailey link with no argument to see where the
current folder points; explicit --app / --org flags always win over the link.
The two folders in that line don’t mean the same thing, and both are needed: the positional
[dir] is where the link lives, --dir <folder> is what it publishes.
--dir <folder>: the folder to publish, relative to the link. Use it when your site is built — the link stays at the repo root, where it survives, and points atbuild/, which your build tool wipes and recreates on every run. Omitting--diron a re-link keeps the folder already recorded;--dir .clears it.
# A built site: link once at the root, then publish with a bare command, forever.bailey link my-site --dir buildnpm run build && bailey deploy # publishes build/, announced before the uploadbailey pull links the folder automatically on first fetch, so the everyday loop is
just: bailey pull my-site → edit → bailey deploy. A pulled folder is the site, so it
gets no --dir.
bailey dev follows the same link: with no folder named, it serves the one --dir records,
so the sandbox and the deploy never disagree on which folder is the site.
bailey pull: fetch a site to edit it
Section titled “bailey pull: fetch a site to edit it”bailey pull <app> [dir] [--org <org>] [--force]Downloads the site’s current version — files, governance manifest
(bailey.manifest.json) and mail templates — into dir (default: the current folder), so
you can edit locally and republish with bailey deploy (the folder comes out linked,
so no flags are needed). The bundle is self-sufficient: a pull → deploy round-trip keeps
your declared buckets and routing intact. It refuses to write into a non-empty folder
unless you pass --force.
bailey dev: local sandbox
Section titled “bailey dev: local sandbox”bailey dev [dir] [--port 8788]Serves <dir> on http://127.0.0.1:8788 with real storage (kv / counter /
collect) so you can test your data wiring before publishing. It’s a throwaway sandbox:
the data is local and disposable, and nothing goes to production. No account needed.
Name no folder in a link that records a --dir and the sandbox serves that one — the same
folder bailey deploy would publish.
bailey list: list your sites
Section titled “bailey list: list your sites”bailey list [--org <org>]Prints a table of your sites — your personal space by default, or an organization’s
fleet with --org:
APP NAME URLmy-site Vengeful Castiel https://my-site.trybailey.app/The APP column is the value the other commands take: bailey pull <APP>,
bailey deploy --app <APP>. The display name doesn’t target anything.
bailey orgs: list your organizations
Section titled “bailey orgs: list your organizations”bailey orgsLists the organizations you belong to, with your role and the slug to pass as --org.
By default every command works in your personal space; add --org <slug> to list,
deploy, pull, data or erase to target a project that lives in an organization
instead. Your rights there are the same as in the dashboard (enforced server-side), and a
new site deployed with --org is created inside that organization.
bailey data: read submissions
Section titled “bailey data: read submissions”bailey data <app> <bucket> [--org <org>]Dumps a collection bucket as JSON lines (owner-only). The dashboard’s Collected data tab does the same with no terminal; see Reading & erasing collected data.
bailey erase: right to erasure
Section titled “bailey erase: right to erasure”bailey erase <app> <email> [--org <org>]Removes every record matching <email> across all of the app’s buckets. The same action is
available from the dashboard under Data & privacy → Erase a person’s data.
bailey version · bailey help
Section titled “bailey version · bailey help”bailey version # prints the installed versionbailey help # or -h, --helpPublish from CI
Section titled “Publish from CI”A minimal GitHub Actions step, once BAILEY_TOKEN is set as a repository secret:
- name: Publish to Bailey run: | curl -fsSL https://dl.trybailey.app/install.sh | sh export PATH="$HOME/.local/bin:$PATH" bailey deploy ./dist --app my-site env: BAILEY_TOKEN: ${{ secrets.BAILEY_TOKEN }}If the site belongs to an organization, add its scope — bailey deploy looks in your
personal projects by default:
bailey orgs # your organizations and their slugbailey deploy ./dist --app my-site --org acmeWithout it the CLI doesn’t find the project, tries to create it, and stops on
subdomain "my-site" is not available (already taken) — the address is taken by your own
project, in a scope it wasn’t looking at. A deploy token scoped to selected projects behaves
the same way: it only ever sees those.
Buckets, declared once
Section titled “Buckets, declared once”Whether you declare buckets here (--public / --collect), in a bailey.manifest.json
shipped with your files, or from the dashboard’s Data & privacy
screen, they reconcile into the same governed set, and writes from the
SDK only work once the bucket exists.