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:
- The CLI starts a tiny local web server.
- It opens your browser to a banto.tv consent page.
- 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:
| Name | Client URL | API URL |
|---|---|---|
prod | https://banto.tv | https://api.banto.tv |
local | http://localhost:3000 | http://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]
}
]
}
}
| Field | What it does |
|---|---|
title | Display name on the banto.tv listing. |
description | Short blurb on the listing page. |
public | false = 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 }
}
| Field | What it does |
|---|---|
role | "host" or "player". When "player", you must also include player. |
state.name | Which state the preview drops you into. Must match a state file. |
state.inputs | Params for that state. Must match the state’s params type. Use null for states that declare no params. |
var | Overrides 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). |
data | Inline data sources. Required for any data block your views read (the preview backend has no concept of your account’s saved sources). |
player | The 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:
| OS | Path |
|---|---|
| Linux / macOS | ~/.config/banto/ |
| Windows | %APPDATA%\banto\ |
The folder holds two files:
config.json— your active environment (prodorlocal).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
| Symptom | Fix |
|---|---|
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.tv” | Check your network. If you’re hacking on the runtime against a localhost server, run banto env local. |
banto publish returns 403 | Your 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 out | Re-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” warnings | A 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. |