Skip to main content

Quickstart

Install Brave Bot with npm, then run bravebot in a project directory to start a session.

npm install -g @brave/bravebot
cd your-project
bravebot

Install​

The install downloads the release binary for your platform and verifies its checksum. macOS, Linux and Windows are supported, on both x86_64 and arm64. To build from source instead, see Development.

On macOS and Linux there is an install script, for a machine with no npm on it:

curl -fsSL https://raw.githubusercontent.com/brave/bravebot/main/install.sh | sh

It fetches the newest release for your platform, checks it against the published checksum, and writes nothing if the two differ. It puts the binary in /usr/local/bin, asking for sudo only if that directory is not yours to write to. INSTALL_DIR puts it somewhere else:

curl -fsSL https://raw.githubusercontent.com/brave/bravebot/main/install.sh \
| INSTALL_DIR="$HOME/.local/bin" sh

Running the line again is how an install made this way is updated. The script records where it put the binary, so a second run with no directory named replaces that one rather than leaving two on your PATH.

Check a download by hand​

Both installers check the binary before they write it, and refuse when it does not verify. To check a release yourself, download the asset for your platform from the releases page, then:

On macOS, the binary has to be signed by Brave's Developer ID team (KL8N8XSYF4) and accepted by Gatekeeper. Both commands print nothing when they succeed:

codesign --verify --deep --strict \
-R '=anchor apple generic and certificate leaf[subject.OU] = "KL8N8XSYF4"' bravebot-darwin-arm64
spctl -a -t install bravebot-darwin-arm64

On Windows, in PowerShell, Status has to be Valid and the signer Brave Software, Inc.:

Get-AuthenticodeSignature .\bravebot-windows-amd64.exe |
Format-List Status, @{ n = 'Signer'; e = { $_.SignerCertificate.GetNameInfo('SimpleName', $false) } }

On Linux the binary carries no signature. Its .sha256 file is signed, and the signature has to be from the key whose fingerprint is 13F28F0405C49B0B232DBA1BC1E827646A2DE416. The installers carry that key themselves; the same key is published at https://brave-browser-downloads.s3.brave.com/keys/bravebot-release.asc. With the asset, its .sha256 and its .sha256.asc in the current directory:

export GNUPGHOME="$(mktemp -d)"
curl -fsSL https://brave-browser-downloads.s3.brave.com/keys/bravebot-release.asc | gpg --import
gpg --fingerprint 13F28F0405C49B0B232DBA1BC1E827646A2DE416
gpg --verify bravebot-linux-amd64.sha256.asc bravebot-linux-amd64.sha256
echo "$(cat bravebot-linux-amd64.sha256) bravebot-linux-amd64" | sha256sum --check

gpg --verify has to say Good signature from a key with that fingerprint, and sha256sum has to say OK.

Configuration is baked into the released binary, so there is nothing to set up. Check what it will actually use:

bravebot doctor
configuration OK
endpoint https://ai-chat.bsg.brave.com/v1/chat/completions
premium https://ai-chat-premium.bsg.brave.com/v1/chat/completions
key id …
model automatic-bravebot (default)
key … (never transmitted)

state directory ~/.bravebot, from HOME

confinement …

network
trust roots built in (SSL_CERT_FILE, SSL_CERT_DIR names others)
proxy none (HTTPS_PROXY, HTTP_PROXY names one, in upper case or lower)

It names the state directory it resolved, or says there is none, why, and what is not kept without one: with no state directory there are no settings of your own, no session to resume, no prompt history and no skills. The network section names the trust roots in force, the proxy, and the hosts it is not used for, which is the first place to look when every request fails with an unknown issuer.

A build with no model service configured does not start work at all. It says so and lists the ways to set one up, each naming what to type or write, rather than running against an endpoint that will not serve it. doctor says the same and fails. See Configuration.

Staying current​

A session that opens on a version something newer has replaced says so, once, under the trust question, and gives the line that updates the copy you are running. The notice names the version you are running rather than the newer one, which may have moved by the time you update: the npm command for an npm install, the script again for a script install. A build from source is told nothing, since neither line would update one.

Nothing about it waits. The notice comes from an answer an earlier launch wrote down, and the request that refreshes it, at most one an hour whether or not it learned anything, runs behind the session and is for the next one. So a first run says nothing, and a release is announced on the launch after the one that first asks for it.

Every way this can fail is silence: no network, a registry that will not answer, an answer of an unexpected shape. A registry that cannot be reached today does not withdraw a version it announced earlier, so the notice keeps showing until the registry answers with something else. A version that is not three numbers is never announced either, release candidates included. An incognito session still reads an answer an ordinary session left, and neither records one nor asks.

The first question: do you trust this directory?​

Brave Bot asks whether you trust the working directory before anything else.

  • Trust it and ordinary work proceeds: files are read as trusted, and edits are not shown to you for every path in the tree.
  • Decline and nothing is trusted. The session still works. Every write is shown to you first, and files are read into quarantine rather than into the model's context.

The answer belongs to the session, not to the directory: every fresh session asks again, whatever you answered last time. --resume restores the answer that session's own user gave. Press r instead of y and later sessions started in exactly that directory trust it without asking, until you run /forget-trust (Remembering the answer).

What that answer means in detail, and every other way a path comes to be trusted, is Trusted directories.

Ask for something​

> what does crates/cli/src/main.rs do?

Brave Bot reads the file, and answers. A read of a file in a trusted directory reaches the model directly. A read of a file nobody vouched for is quarantined, and you are offered the chance to vouch for that one file at the moment it matters:

╭ let the model read this file? ────────────────────────────╮
│Trust game.js │
│ │
│ the model cannot read this file, so it is working blind │
│ on it. Vouching lets it read this file for the rest of │
│ this session, here and in every later read. │
│ │
│┃ const SPEED = 100; │
│ │
│ y trust it n leave it quarantined ctrl-c stop │
╰───────────────────────────────────────────────────────────╯

Ask for a change​

> add a --quiet flag that suppresses the progress line

Every write and every edit is put to you before it happens. An edit is shown as a diff, which is why the agent prefers edit_file to rewriting a whole body. Declining is not cancelling: the turn carries on and can try something else. Ctrl-C refuses and stops.

Run something​

> run the tests

A run prompt shows the compiled plan: every step, the binary each resolved to, the directory, and every file the line would write. A step whose name reached its binary through a link, such as a virtualenv's python, shows the link and then the binary, as link -> binary. The prompt also says that the command is not sandboxed:

y run it a always n don't ctrl-c stop the turn

a is a standing permission for that exact command in this session, and it grants two things together: the command runs again unasked, and what it prints is read as trusted rather than coming back as a reference. See the run tool.

Or run it yourself. Type ! on an empty prompt and the line becomes a command for your own shell:

! cargo test

Its output goes to the model in full, so the next thing you type can be "fix the first failure".

One-shot and piping​

bravebot "what does src/main.rs do?" # one-shot
bravebot "explain this" --file notes.md # with named context
gh pr diff | bravebot -p "summarise this" # with piped input

A one-shot run refuses effects rather than applying them unseen, because there is nobody to ask. Piped input is untrusted and private, always. See Non-interactive use.

Where to go next​