~ / docs / cli

CLI reference

banto is the only command you need to install. It compiles your .banto files, previews your game in the browser, and publishes it to banto.tv.

If you’ve never used it, start with Getting started; this doc is the keep-it-open-while-you-work reference.

Install

npm install -g @banto/cli
banto --help

You can also install per-project (npm install --save-dev @banto/cli) and invoke as npx banto ….

Subcommands

banto init <dir>

Scaffolds a new project at ./<dir>. The directory must not already exist (or must be empty). The starter is the empty lobby template: host shows the room code with a kick list, players see a “you’re in” message.

banto init my-game

Files created:

my-game/
├── globals.banto
├── start.banto
├── styles.banto.css
├── banto.config.json
├── banto.preview.json
└── .gitignore

banto build

Compiles the project to a single game.json IR file at the project root. Run it from anywhere inside the project — the CLI walks up until it finds globals.banto.

banto build              # quiet
banto build --verbose    # print per-file progress

Output on success:

Wrote ./game.json (487 bytes, 0 error(s), 0 warning(s)).

On a syntax/type error, you get the same diagnostics your editor shows, then a non-zero exit code:

start.banto:14:17 error [banto.cstate-write-not-top-level]: …
Compilation aborted: 1 error(s), 0 warning(s).

game.json is a build artifact — keep it out of version control (the starter’s .gitignore already does this).

Browser studio (local daemon)

For a Lovable-style split editor + live preview in the browser, run the app with the API server (Studio compiles on the server, not a local WebSocket daemon):

# Studio compiles via the @banto/cli in the sibling ../banto-dsl checkout
# (build it once there: cd ../banto-dsl && npm install && npm run build)
yarn dev       # client + server

Open /banto-dsl/studio or start from /create. The server scaffolds projects, runs banto build, and serves the preview bundle to the client.

banto preview

The inner-loop command. Compiles, uploads the result to the Banto preview API as a short-lived bundle, and opens the preview screen in your browser pre-seeded from banto.preview.json.

banto preview              # default — opens your browser
banto preview --no-open    # just print the URL (handy in containers / CI)

Output:

Wrote ./game.json (…).
Uploaded preview bundle to https://api.banto.tv (id: 7f3a8e…).
Opening https://banto.tv/banto-dsl/preview?bundleId=7f3a8e… in your browser…

The preview bundle expires after 10 minutes on the server. If you walk away and come back, just re-run the command.

banto auth

Logs you into banto.tv using a browser-based loopback flow:

  1. The CLI starts a tiny local web server.
  2. It opens your browser to a banto.tv consent page.
  3. You approve, banto.tv redirects to localhost, and the CLI captures the bearer token.
banto auth

You only need to run this explicitly the first time. banto publish will trigger the same flow automatically if your token is missing or expired.

banto publish

Compiles your project and ships it to banto.tv. The settings in banto.config.json (title, description, default datasets) become your game’s listing.

banto publish

Re-running banto publish after edits updates the existing game in place — same ID, no duplicate listing. The CLI uses banto.lock.json (sibling of banto.config.json) to remember which remote game your project is bound to.

Publishing is admin-gated on banto.tv by default. If you get a 403, your account doesn’t have publishing permissions in the active environment.

banto env [<name>]

Shows or switches the active environment. The CLI ships with two:

NameClient URLAPI URL
prodhttps://banto.tvhttps://api.banto.tv
localhttp://localhost:3000http://localhost:8080
banto env              # show the current env
banto env local        # switch to localhost (for runtime contributors)
banto env prod         # switch back

Almost every user wants prod — the only reason to switch is if you’re running banto.tv’s backend yourself.

Config files

banto.config.json (per project)

How your game appears on banto.tv. Lives next to globals.banto.

{
    "title": "Grant's Trivia Tournament",
    "description": "It's like Trivia, but as a tournament!",
    "public": false,
    "default": {
        "questionSet": "this"
    },
    "new": {
        "questionSet": [
            {
                "prompt": "Which of these are programming languages?",
                "options": ["Python", "HTML", "JavaScript", "HTTP"],
                "correctOptions": [0, 2]
            }
        ]
    }
}
FieldWhat it does
titleDisplay name on the banto.tv listing.
descriptionShort blurb on the listing page.
publicfalse = only you and people with a direct link can find it. true = listed in the public catalog.
default.*For each data block your project declares (questionSet, promptSet, or dynamic), the data source pre-selected when a host starts a game. Use a banto.tv data-source ID, or the literal "this" to point at the matching new.* entry.
new.*Inline contents of a fresh data source to create on banto.tv as part of publishing. Shape matches the data block: questions for questionSet, strings for promptSet, or a (string | number | (string | number | (string | number)[])[])[] list for dynamic.

banto.preview.json (per project)

Seed values for the preview screen. Lives next to globals.banto.

{
    "role": "host",
    "state": { "name": "start", "inputs": null },
    "var": {
        "roomCode": "ABCD",
        "players": { "p1": { "name": "Alice", "score": 0 } }
    },
    "data": {
        "questionSet": [{ "prompt": "...", "options": ["..."], "correctOptions": [0] }]
    },
    "player": { "sessionId": "p1", "name": "Alice", "score": 0 }
}
FieldWhat it does
role"host" or "player". When "player", you must also include player.
state.nameWhich state the preview drops you into. Must match a state file.
state.inputsParams for that state. Must match the state’s params type. Use null for states that declare no params.
varOverrides for any var block. You can omit a var and the CLI will fill it from the declared default (when the default is statically reducible).
dataInline data sources. Required for any data block your views read (the preview backend has no concept of your account’s saved sources).
playerThe player record presented when role: "player".

This file is how you test states other than start.banto without manually playing through the whole game. Set state.name to the one you’re working on and seed the vars/data it expects.

Where credentials live

banto auth saves your bearer token outside the project, scoped to your OS user:

OSPath
Linux / macOS~/.config/banto/
Windows%APPDATA%\banto\

The folder holds two files:

  • config.json — your active environment (prod or local).
  • credentials.json — the bearer token. Treat it like a password.

You don’t normally need to edit these by hand. banto env writes the former, banto auth writes the latter.

Troubleshooting

SymptomFix
banto build says “no globals.banto found in this directory or any parent”You’re not inside a Banto project. cd into one or run banto init <name>.
banto preview says “could not reach https://api.banto.tvCheck your network. If you’re hacking on the runtime against a localhost server, run banto env local.
banto publish returns 403Your account isn’t an admin on the active environment’s banto.tv. Publishing is admin-gated by default.
banto init says “target is not empty”Pick a different name, or move the existing files out. There’s no --force flag.
The browser-opened consent page errors outRe-run banto auth. The loopback listener uses a random port and the previous attempt’s port may have been blocked.
Preview opens but the page says “bundle not found or expired”Bundles live for 10 minutes. Re-run banto preview to upload a fresh one.
Preview opens but I see “Var X has no static default” warningsA var’s default uses an expression like func.currentTime() that the CLI can’t reduce statically. Add an explicit value to banto.preview.json’s var block.