CLI Tool

The avsb CLI brings platform work to your terminal. Clone an experiment, edit the variation code in your own editor, watch changes appear in a real browser as you save, and push the finished code back. It also lists and toggles feature flags, manages metrics, metric bindings, and datasets, relays webhook deliveries to your machine, and generates TypeScript types for your feature flags.

Every read command can print JSON instead of a table, so scripts and agents do not have to scrape coloured text. See Machine-readable output.

Installation

Install the CLI globally with npm. You need Node.js 18 or later.

Shell
npm install -g @avsbhq/cli
Shell1 line

Check the version:

Shell
avsb --version
Shell1 line

Getting started

If you are setting up a feature flags project in your own application, one command does the whole first run, ending with proof that your app checked in:

Shell
npx @avsbhq/cli init
Shell1 line

See CLI Setup Command. The steps below are the experiment workflow: cloning a web experiment, editing its code locally, and pushing it back.

1

Install the CLI

Run npm install -g @avsbhq/cli. This installs the avsb command globally, so you can use it from any directory.

2

Authenticate

Run avsb login and paste a personal access token when prompted. Create one in Account Settings > Personal Access Tokens in the dashboard. The token is saved in ~/.avsb/config.json as plain text with file mode 0600, and reused until you log out. For scripts and CI, set the AVSB_TOKEN environment variable instead: see CLI Authentication.

3

Clone an experiment

Find the experiment's short ID (the number shown in the experiments list) and run avsb clone <shortId>. A folder named after the experiment is created. Script and style languages come from the experiment's own settings on the platform, so the CLI does not ask you to choose them.

4

Start the dev server

Move into the cloned folder and run avsb dev. It watches your files and broadcasts changes to the A vs B Chrome extension. The server takes the first free port between 4400 and 4409 and prints the one it took. Open your target website in Chrome with the extension installed, and it connects automatically.

5

Edit and preview

Open the folder in your editor. CSS and SCSS changes are swapped into the page without a reload; JS and TS changes reload the page so the new code runs clean.

6

Push your changes

Run avsb push. The CLI compiles your files, warns you if the platform copy changed since your last sync, and uploads the result. If the experiment is running or paused, it offers to publish the change immediately, otherwise the change waits as a pending update for review.

Logging in looks roughly like this:

Shell
$ avsb loginPaste your personal access token: ********Token verifiedLogged in to Acme Corp as jane@example.comToken saved in plain text at /Users/jane/.avsb/config.json (file mode 0600).
Shell5 lines

Then clone, develop, and push:

Shell
avsb clone 300015cd homepage-hero-testavsb devavsb push
Shell4 lines

Command groups

Every group the CLI ships. All of them need a token already in place except avsb login (which supplies one), avsb logout, avsb status, avsb agents-md (these two touch only local files), and avsb completion (it prints a script and asks the platform nothing).

GroupWhat it doesReference
avsb initSet up a project in the current folder and prove it worksCLI Setup Command
avsb agents-mdWrite A vs B instructions into CLAUDE.md and AGENTS.mdCLI Setup Command
avsb loginSave a personal access token on this machineCLI Authentication
avsb logoutDelete the saved loginsCLI Authentication
avsb whoamiShow which account and organization the token reachesCLI Authentication
avsb orgShow, list, and switch the active organizationCLI Authentication
avsb cloneClone an experiment into a local folderThis page
avsb statusShow what the local manifest holdsThis page
avsb pullRefresh local files from the platformThis page
avsb pushCompile and upload local changesThis page
avsb devWatch files and hot reload through the extensionThis page
avsb projectPull, push, and watch the project scriptThis page
avsb experimentsList experiments in a projectThis page
avsb flagsList, read, create, rename, and toggle feature flagsThis page
avsb metricsManage tracking definitionsCLI Metrics Commands
avsb metric-bindingsManage how metrics are measuredCLI Metrics Commands
avsb codegenGenerate TypeScript types for your flagsCLI Codegen
avsb find-refsFind flag keys in your source and compare them with the platformCLI Codegen
avsb datasetsPush and activate dataset versionsDatasets API and CLI
avsb listenWatch webhook deliveries and forward them to a local URLWebhooks: local development
avsb triggerSend a sample webhook event to your webhooksWebhooks: local development
avsb openOpen a dashboard page in your browserThis page
avsb completionPrint a shell completion scriptThis page

Experiment commands

avsb clone <url | shortId>

Downloads an experiment into a local folder named after the experiment. Pass the numeric short ID, the EXP- form, or the full dashboard URL.

Shell
avsb clone 300015avsb clone EXP-300015avsb clone https://app.avsb.cloud/projects/123/experiments/300015
Shell3 lines

The experiment's script and style languages are read from the platform and recorded in the .avsb.json manifest, along with the experiment and variation IDs. Do not delete that file: every other command in the folder reads it.

avsb status

Prints what the manifest in the current folder holds: the experiment name, its EXP- ID, its status, the variation count, the script and style languages, when you last synced, and the platform URL.

Shell
avsb status
Shell1 line
Status is a local read

avsb status does not contact the platform, so it cannot tell you whether the platform copy has moved on. avsb push is what checks that: it hashes the platform's current code before uploading and warns you when it differs from your last sync.

avsb pull

Fetches the experiment's current code and updates your local files. Use it when someone changed the code in the web editor.

Shell
avsb pullavsb pull --force   # skip the local-change check
Shell2 lines
Pull overwrites local changes

avsb pull replaces your local variation files with the platform's version. It lists the files it would overwrite and asks first, unless you pass --force.

avsb push

Compiles your local files and uploads both the source and the compiled output. Compile errors are printed with file, line, and column, and nothing is uploaded until they are fixed.

Shell
avsb pushavsb push --force       # skip the remote-change checkavsb push --publish     # publish without the question (running or paused experiments)avsb push --no-publish  # leave the change pending without the question
Shell4 lines

After a successful push, if the experiment is running or paused, the CLI asks whether to publish the change now or leave it pending for review. Publishing puts the new code on your live site within seconds, exactly like Publish changes in the dashboard. A draft is saved without the question. A refused upload names the file in your folder and the field, for example variant-a/variant-a.ts (variations.1.controlJs.source): Variation code must define an initVariation(options) function.

avsb dev

Starts the file watcher and the local WebSocket server the Chrome extension connects to. It takes the first free port between 4400 and 4409, so a busy 4400 is not a problem, and prints the port it took.

Shell
avsb dev
Shell1 line

Keep it running while you work. Press Ctrl+C to stop.

You need the Chrome extension for avsb dev

avsb dev broadcasts file changes; it does not open a browser for you. Install the A vs B Chrome extension from the Chrome Web Store or download it directly, then open your target website in Chrome to see live updates. See Chrome Extension for full setup.

Feature flag commands

Flag commands read and write through the public API, using the same personal access token as everything else. They act on the project named by --project, or on the project recorded in the folder you are standing in.

Shell
avsb flags list --project PRJ-10avsb flags get checkout_v2 --project PRJ-10avsb flags create checkout_v2 --project PRJ-10avsb flags create greeting --type STRING --variation control=hello --variation variant=hi --default controlavsb flags toggle checkout_v2 --env production --offavsb flags update checkout_v2 --name "Checkout v2"
Shell6 lines

avsb flags list

One row per flag: its FLG- id, key, type, status, and which environments are serving it. Long lists page with --limit and --cursor; the next cursor is printed when there is more to fetch.

avsb flags get <flag>

The full flag: its variations, and every environment with its state and whether it has unpublished changes. Accepts the flag key, the numeric short id, or the id.

How a key is matched

The API addresses a flag by short id or id, not by key. When you pass a key, the CLI finds the matching flag in the project first and prints what it matched (Matched key checkout_v2 to FLG-12), so the target is never a guess. Passing the short id skips that lookup.

avsb flags create <key>

Creates a flag. Boolean flags get on=true and off=false without you typing them; other types need at least two --variation <key>=<value> pairs. --default picks the variation served when no rule matches. A new flag serves nothing until a rule is added and its environment is running.

avsb flags toggle <flag> --env <environment>

The kill switch. --off stops one environment serving that flag's rules; --on starts it again. Both are safe to run repeatedly: asking for the state it is already in succeeds and reports that nothing changed, so an incident script can fire it blind.

avsb flags update <flag>

Changes the name, description, or key. --description "" clears the description. Before writing, the CLI reads the flag and sends its version back, so a change someone else made in between is refused instead of overwritten. When that happens, read the flag again and rerun. --force writes without the check, and --if-match <version> uses a version you already hold.

Experiment listing

Shell
avsb experiments list --project PRJ-10
Shell1 line

One row per experiment: its EXP- id, status, name, and when it last changed. Use avsb clone EXP-<id> to edit one locally.

Opening the dashboard

Shell
avsb open                 # this project's dashboardavsb open flags           # the flags pageavsb open snippet         # the install snippetavsb open EXP-42          # one experimentavsb open tokens --url    # print the link instead of opening it
Shell5 lines

Targets: dashboard, experiments, flags, environments, metrics, datasets, settings, snippet, docs, tokens, plus EXP-<id> and PRJ-<id>.

Shell completion

Shell
avsb completion bash   # add to ~/.bashrc:  eval "$(avsb completion bash)"avsb completion zsh    # add to ~/.zshrc:   eval "$(avsb completion zsh)"avsb completion fish   # avsb completion fish > ~/.config/fish/completions/avsb.fish
Shell3 lines

The script is printed, never installed for you, so you choose where it goes.

It completes at every level, not just the first word: subcommands inside their group (avsb flags li<Tab> gives list, not listen), each command's own flags (avsb flags toggle checkout_v2 --o<Tab> gives --off and --on), the shell names after avsb completion, and the targets after avsb open. It is generated from the installed CLI, so upgrading the CLI and loading the script again picks up new commands and flags.

Machine-readable output

Every read command takes --json and prints exactly one JSON document on stdout:

Shell
avsb flags list --project PRJ-10 --json
Shell1 line
JSON
{  "ok": true,  "command": "flags list",  "data": [],  "meta": { "page": { "nextCursor": null, "hasMore": false } }}
JSON6 lines

data is the platform's own response body, unchanged. Anything about the response rather than the resource (the page cursor, a resource version) rides in meta.

A failure uses the same envelope and passes the platform's own error through:

JSON
{  "ok": false,  "command": "flags update",  "error": {    "code": "precondition_failed",    "message": "The resource changed since you read it. Re-read it and retry.",    "status": 412,    "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#etag--if-match"  }}
JSON10 lines

Codes starting with cli_ mean the CLI stopped before asking the platform (no project named, not logged in, a value it could not parse), or that the platform never answered. Everything else is the platform's own error code, documented at the docUrl in the body.

When the platform cannot be reached, the code is cli_network (exit code 1) and the message names the host and what went wrong, for example Cannot find app.avsb.invalid: the name does not resolve (DNS lookup failed). or Nothing is listening at localhost:3000: the connection was refused. An API URL that is not a web address at all, such as AVSB_API_URL=notaurl, stops with a usage error (exit code 2) before any request. A server that answers with something other than the platform's error format is named too: example.com answered HTTP 404, which is not an A vs B API response. Check the API URL.

Five more rules hold in every mode:

  • Results go to stdout; progress, warnings, and errors go to stderr. So avsb metrics list --json > metrics.json leaves a valid file and still shows you what went wrong.
  • A refusal prints its reasons, not only its summary: each field that failed validation is named with the reason, for example key: Key must be lowercase alphanumeric with underscores. With --json the same reasons are in error.details.issues.
  • --quiet prints the result and nothing else: table rows, Email: … style fields, a completion script, or a URL still print, while progress notes, headings and blank lines do not. Warnings and errors still go to stderr. eval "$(avsb completion bash)" works with AVSB_QUIET=1 set.
  • AVSB_JSON=1 and AVSB_QUIET=1 do the same as the flags, for a whole script.
  • A command never asks a question it cannot get an answer to. With no terminal, CI set, --no-input, or --json, a step that would ask stops instead and names the flag that answers it: avsb pull --force, avsb push --force or --publish, avsb org switch <org>, avsb metrics delete <id> -f, avsb datasets rollback <slug> -f.

Exit codes

CodeMeaning
0Success
1The command ran and failed
2The command was called wrongly: unknown option, missing argument, bad value
3Not logged in, or the platform rejected the token
4The resource changed or refuses the change: re-read it and retry
Shell
avsb flags toggle checkout_v2 --env production --off --json || case $? in  3) echo "refresh AVSB_TOKEN" ;;  4) echo "someone else changed it; re-read and retry" ;;esac
Shell4 lines

Project script commands

Project scripts run on every page where your snippet is active, independent of any experiment.

Shell
avsb project pull PRJ-10   # or: avsb project pull 10avsb project push          # --force to skip the conflict checkavsb project dev
Shell3 lines

avsb project pull creates a project-<id>/ folder holding the script, an .avsb-project.json manifest, and, for TypeScript projects, a tsconfig.json plus avsb.d.ts and variation-code.d.ts. Those two are copies of the published @avsbhq/snippet-types declarations, so your editor knows the same avsb API the snippet ships. Running avsb project pull again updates the script and refreshes the declarations, in place: from inside project-<id>/ or from the folder that holds it, never as a nested copy. Local edits to the script are listed before they are overwritten, and --force overwrites them without asking.

avsb project push saves the script as unpublished changes, the same as saving in the dashboard editor. Your live site keeps the published script until you press Publish on the project's Snippet settings.

Cloned folder layout

Plain text
homepage-hero-test/├── .avsb.json           ← Manifest: experiment ID, variation IDs, languages├── tsconfig.json        ← TypeScript experiments only├── avsb.d.ts            ← TypeScript experiments only: the window.avsb API├── variation-code.d.ts  ← TypeScript experiments only: options, activate, track├── trigger.ts           ← Trigger code: when the experiment activates├── control/│   ├── control.ts       ← Control variation code│   └── control.scss     ← Control variation styles (usually empty)└── variant-a/    ├── variant-a.ts     ← Variant A code    └── variant-a.scss   ← Variant A styles
Plain text12 lines

File extensions follow the experiment's languages (.js or .ts, .css or .scss). trigger.ts is editable: avsb push uploads it with the variation files.

The two .d.ts files are copies of the published @avsbhq/snippet-types declarations, so autocomplete matches what the snippet actually ships. They are rewritten on every avsb pull, so upgrading the CLI upgrades the types. Do not edit them; anything you add is overwritten.

When a command is refused

A valid token is not always enough. Two things can stop a command that worked yesterday, and neither is fixed by logging in again or issuing a new token.

  • Your organization is suspended. clone, pull, push, and anything else that reads or changes your data are refused for as long as the suspension lasts. avsb login, avsb whoami, and avsb org keep working so you can confirm which organization you are pointed at. Suspension applies to the CLI exactly as it does to the dashboard and the API.
  • The feature you are using is switched off. If web experiments have been switched off for your organization, commands that work with experiments are refused until the feature is switched back on.

In both cases the command fails with a short message saying why. See A Feature or Action Is Unavailable for what each message means and what to do about it.

Was this helpful?