Terminal client reference

bubble-tui connection flags, profiles, credentials, interactive commands, keyboard shortcuts, and scriptable output.

Referencedocs/reference/30-terminal-client.mdx
On this page

bubble-tui runs an interactive session when called without a command, or a single scriptable command when one is supplied. For installation, a first conversation, and both ways to provision bot tokens, start with the terminal client quickstart.

Profiles and credentials

bubble-tui --help prints usage without connecting. The default profile is <bubbleHome>/tui/config.yaml. On a fresh installation, bubbleHome is ~/.bubble; set BUBBLE_HOME to choose another directory. The SDK also honors the legacy OCTOSTAFF_HOME variable and falls back to an existing ~/.octostaff directory when ~/.bubble does not exist.

A profile can contain just the server URL and use interactive login:

yaml
bubble:
  url: http://localhost:3000

For a configured bearer token, reference an environment variable:

yaml
bubble:
  url: http://localhost:3000
  token:
    env: MY_BUBBLE_TOKEN
  # Optional: only used by the master-key driver.
  principalId: root

Store a named profile at <bubbleHome>/tui/profiles/staging.yaml and select it with bubble-tui --profile staging. Alternatively, use bubble-tui --config ./staging.yaml. An explicitly selected file must exist; the default profile file is optional. --config ./staging.yaml uses the file's basename, staging, as its credential profile, just like --profile staging. Files with the same basename share that credential profile; credentials are also checked against the server URL.

Connection settings take precedence in this order: CLI flags, environment, profile file, then the default server URL http://localhost:3000.

FlagEnvironment variablePurpose
--base-url <url>BUBBLE_URLBubble server URL
--token <token>BUBBLE_TOKENBearer credential
--principal <id>BUBBLE_PRINCIPAL_IDPrincipal for master-key authentication
--profile <name>—Select a named profile
--config <path>—Select an explicit profile file; takes precedence over --profile
--resume <thread>—Open a thread after authentication

Without a configured token, the TUI uses saved credentials for the selected profile and matching server URL, or offers the server's login methods:

  • local-token: enter a token issued by Bubble.
  • master-key: enter the server key and an optional principal ID.
  • default: enter a principal ID for a development server.
  • auth0: authorize in a browser using the displayed URL and code. Bubble must advertise an Auth0 Native client ID and issuer. The Native app's client secret is never used. Access tokens refresh automatically when a refresh token is available.

Entra device login is not implemented; use a configured bearer token for that driver. See the server authentication guide for Auth0 device-flow setup.

Interactive login and the login subcommand save credentials in <bubbleHome>/tui/credentials.json, keyed by profile and checked against its server URL. It is written with mode 0600, and each Auth0 refresh replaces the saved tokens, including a rotated refresh token. The file contains secrets; keep it out of version control. /logout disconnects and removes that profile's saved credentials. It does not revoke tokens or remove credentials supplied through flags, environment variables, or profile files.

Interactive commands

Type these inside the TUI:

CommandAction
/helpList available commands
/loginChoose a login method and reconnect
/logoutDisconnect and discard this profile's saved credentials
/whoamiShow the authenticated principal
/threadsBrowse the threads you can see and open one
/new [@principal …] [title]Create a thread with you and anyone you name, and open it
/open <threadId>Open an existing thread
/invite @<principal> [role]Add a principal to the open thread
/title <text>Set the open thread's title
/principals new <id> [--name "Display name"]Create a bot and show its first token once
/tokens list <id>List a bot's token metadata
/tokens mint <id>Mint another token and show its secret once
/tokens revoke <id> <tokenId>Revoke one token
/quitExit

Other slash-prefixed text is sent as ordinary prose. Ctrl+D exits the TUI.

Keys and composing

These keys apply while composing:

KeyAction
EnterSubmit the draft; an exact client command runs locally
Ctrl+JInsert a newline without submitting
Left / RightMove the caret
Up / DownMove between draft lines; at the first / last line, recall previous / next history
Ctrl+A / Ctrl+EMove to the start / end of the current line
BackspaceErase the character before the caret
TabInsert the selected command or principal completion
Up / Down with completion openSelect a completion row
Ctrl+POpen pending approvals and result requests
Ctrl+CInterrupt a live run; with several runs, open a picker
Ctrl+C again within two secondsExit
Ctrl+DExit

Walking forward past the newest history entry restores the draft that was being typed. History is local to the session. Backspace uses the terminal's DEL byte; forward delete is not supported. Enter submits even when completion is open; use Tab to select first.

Typing / opens one palette with two sections. Client rows are the commands in the table above, which perform client operations without posting a chat message. Thread rows are commands the agents in the thread advertise, each attributed to the principals offering it. Tab inserts the selected row, and the arrow keys choose between them.

A Thread command is sent as a command the agent applies only when it is picked from the palette. The same name typed out by hand is ordinary text, because the protocol forbids a client from inferring a command from slash-prefixed content. Editing the inserted command afterwards, or an agent withdrawing it before the message is sent, turns it back into text rather than sending something no one will act on. Everything after the command is its argument, so one message carries at most one command.

Naming a bot at the start of a draft — @claude /mode — narrows the palette to that bot's advertised commands.

In /threads, use the arrow keys and Enter to open a row; Esc closes the list. The list updates live as threads are created, renamed, or take new events.

An @ opens principal completion. In a message it offers the thread's own participants, since they are who will see it. In /new and /invite it reaches further: the principals this session has already seen, alongside the server's search results, because bots are not substring-discoverable by default — an exact principal ID always works, typed in full.

/invite takes a participant role: commenter, approver, tool_runner, or member (the default, and the union of the others). Non-participant roles such as reader are refused, since granting one would leave the invitee out of the roster with nothing to explain why.

Opening a thread loads its complete history before streaming live events, so no event is missed or shown twice at the boundary. The status line reports the backfill while it runs.

The transcript shows each message under its author, with a glyph for whether they are a person or a bot, elapsed time on a run still in flight, and a marker when someone continues another principal's run. Tool calls render as cards with their input, result, status and approval verdict; joins and invitations render as their own line. A part this version has no card for is named rather than dropped, so nothing an agent sends disappears silently.

Answering an agent

When an agent needs a person before it can continue — permission to run a tool, or a result it cannot produce itself — the status line shows how many of those are waiting on you. Ctrl+P opens them, oldest first, starting with the ones addressed to you.

KeyAction
Ctrl+POpen the queue of waiting requests
aApprove the tool call
rStart a rejection; type a reason and press Enter
EnterSend a typed result for a request
TabMove to the next waiting request
EscDefer — the request stays in the queue

Nothing is sent when you press r: the rejection goes only on the following Enter, and Esc backs out of it without deciding. Esc on a card defers it and never answers it.

The cards are a view of the thread, not of this terminal. Anyone else with the right role can decide first, and when they do the card disappears here. A request naming someone else is shown attributed to them and stays answerable, since the name is a hint and the server decides. If your role on the thread cannot review approvals or return results, the card is still shown — with the reason — so you can see what the thread is waiting on.

A result is sent as JSON when what you type parses as JSON, and as plain text otherwise.

Ctrl+C interrupts a run. With more than one run in flight it asks which, because stopping the wrong agent cannot be undone. Pressing it twice within two seconds exits the TUI. In the run picker, Up / Down selects a run, Enter requests its interruption, and Esc cancels selection. After the two-second window expires, Ctrl+C starts a fresh interrupt attempt.

Scriptable commands

Commands run without the interactive UI and use the same profile selection, connection overrides, and saved credentials. bubble-tui --help lists their syntax. Connection flags can appear before or after a command; unknown flags and invalid arguments fail before any request is made. With no command, bubble-tui requires both stdin and stdout to be terminals.

sh
# Save a validated login for the current profile (prefer an environment token).
BUBBLE_TOKEN=YOUR_KEY bubble-tui login --driver master-key --principal root
bubble-tui whoami

# Create a thread, include an agent, and send quoted prose.
thread=$(bubble-tui new @agent-claude "Release review")
bubble-tui invite "$thread" agent-codex member
bubble-tui send "$thread" "Please review the release notes."
bubble-tui threads --json
bubble-tui tail "$thread" --follow --json

For Auth0, run bubble-tui login --driver auth0 and open the URL printed on stderr to authorize the displayed device code. Login never reads stdin or opens the TUI. Token-based drivers require a token from a flag, environment, or profile. If the server advertises multiple applicable methods, select one with --driver. A successful login validates the identity and saves the credential; a rejected login leaves an existing saved credential intact. Other commands use configured or saved credentials, refresh saved Auth0 tokens when needed, and fail with an error if a fresh login is required.

CommandStandard output
login [--driver <driver>]Authenticated principal ID after saving credentials
whoamiAuthenticated principal ID
threads [--json]Thread IDs and quoted titles; --json emits an array of thread objects
new [@principal …] [title]Created thread ID
invite <thread> <principal> [role]Principal, role, and thread ID, separated by tabs
send <thread> <text>Persisted user run ID
tail <thread> [--follow] [--json]Sequenced Bubble events
principals new <id> [--name <name>]New bot's initial bearer token
tokens mint <id>Newly minted bearer token

Token listing and revocation use the interactive /tokens list and /tokens revoke commands.

tail prints the complete event history through the head observed at startup. --follow continues polling from the next unseen sequence every second. JSON output is newline-delimited JSON: one complete event object per line, suitable for tools such as jq. Plain output prefixes each JSON event with its sequence and type, separated by tabs. These are protocol events, including message chunks and run lifecycle events, rather than assembled transcript messages.

Quote send's text as one shell argument. Slash-prefixed text remains prose. Use -- to pass literal arguments beginning with a dash:

sh
bubble-tui send "$thread" -- "--this is message text"

Results go to stdout; errors and device-login instructions go to stderr. Successful commands exit 0, failures exit 1, and SIGINT/SIGTERM stop a running command with exit code 130/143. Closing a pipe early, for example with head, exits cleanly. Output waits for the consumer before reading another history page.

Bot creation and token minting print the secret once and do not save it in the TUI credential file. Capture that output directly into the agent's secret configuration. For example, bubble-tui principals new agent-review --name "Review bot" performs the same provisioning as the interactive /principals new command. See the bot provisioning guide.