Skip to main content
The artbucket CLI reads and writes a brand folder through the sync API, and uploads the files under assets/ the library doesn’t have yet. It works against any Artbucket server, Artbucket Cloud or your own.

Install and sign in

The CLI is the artbucket package on npm, for Node 22 and later:
login signs in through the browser and keeps a key in ~/.config/artbucket/credentials.json, with that server as the default. It asks for write, since pushing a brand edits it; the consent screen never offers more than you have. artbucket logout forgets the key; disconnect it on the Connections page to revoke it. Without signing in, two variables say where and as whom: A key for CI is made by a workspace admin, in the app (Agents) or with POST /api/v1/keys. Pushing takes write on the workspace; --publish also takes sharing, which a grant can switch off.

The brand a command acts on

Every brand command acts on the brand --brand names, or else the one the slug: in the folder’s brand.yaml names. Never the workspace’s default: a folder pushed without either is refused. pull writes slug:, so after the first pull the folder says which brand it is. The folder is the command’s first argument, brand when left out.

brand pull

Writes the brand as files into the folder:
  • Only files whose meaning changed are written: one that says the same keeps its comments and layout.
  • A file of rules/ or pages/ the brand no longer has is removed.
  • A file you named .yml keeps its name.
  • --assets gives every asset the brand points at a path under assets/, named after its filename, and downloads the ones whose bytes the folder doesn’t already hold. A folder whose assets/ already holds files pulls this way without the flag.
  • A file already in assets/ keeps its path, wherever it sits, matched by the SHA-256 of its bytes: references to it stay paths, never ids.
Without --assets and with an empty assets/, assets are written as asset ids, unless the brand’s Git integration holds them as files.

brand diff

What a push would change, and every problem in the files, writing nothing. Lines start with + (added), - (removed), ~ (changed) or > (a page moved in the tree); ! is a warning or a conflict. It exits 1 on any error in the files, each printed at its file and line:
A file under assets/ the server doesn’t have yet is not a problem: push uploads it. diff lists it and exits 0, and shows the rest of the change once the file is in the library:

brand push

Takes the brand from its files:
  1. Hashes every file under assets/, checks the files, and uploads each file they point at that the library doesn’t have yet.
  2. Writes the brand as one version of its history, so it is undone like any other edit, or prints nothing changed.
  3. Publishes, if asked.

What a push overwrites

A push merges with the app’s edits only when the brand has a sync base: the files both sides last agreed on, which a Git integration records at each commit. A brand synced only by the CLI or CI has none, so a push takes the files whole, and an edit made in the app since your last pull is undone (it stays in the brand’s history). diff shows it first, as a change back to what the files say:
With a sync base, a push keeps those edits instead, and ends with The brand holds changes these files lack: artbucket brand pull brings them in. Pull before you push when people also edit the brand in the app, or keep edits on one side: the repository, with CI pushing it.

From CI

A CI job checks the folder on pull requests and pushes it from the main branch. Keep the key as a secret, with the server’s address beside it.
  • ARTBUCKET_URL is your own server when you host one. On GitLab, ARTBUCKET_URL and ARTBUCKET_KEY are CI/CD variables, the key masked.
  • With --note, each push to main is released with its commit’s first line. Leave --note out to update the draft only, and release it from the app.
  • The check on a pull request reads the brand with the key, so it needs the secret: pull requests from forks, which get no secrets, can’t run it.
  • A pull request that adds a file under assets/ passes the check: diff lists the file, and the push on main uploads it.
  • A CI push has no sync base, so the repository is the source of truth: edits made in the app are undone by the next push. For both sides at once, use a Git integration.

Without the CLI

Everything the CLI does is a few calls to the sync API, which any language can make: Sync API.