Running Commands
BOR runs real shell commands on your machine. This is how it installs dependencies, runs builds and tests, starts dev servers, and drives any CLI. The command tools live inserver/protocol/handlers/exec.js.
execute_command
&&, ||, ;, cd, subshells, env-var expansion, and quoting. (Earlier builds ran commands without a shell, which broke cd X && npm … — that’s fixed; commands now run via /bin/bash -c.)
- Body = the command (CDATA if it contains
<). cwd= working directory (optional).- Output streams live into a terminal card in the bubble, with stdout/stderr and exit status.
- Stdout is captured up to 64 KB, stderr up to 32 KB; the model sees a compact preview with a
run_idfor paging.
The hard 60-second rule
A command never blocks the model longer than 60 seconds.- If it finishes first, you get its full result.
- If it’s still running at 60s, you get the output captured so far plus a
run_id, and the process keeps running in the background — it is not killed.
wait_until to pause, then read_command_tail to fetch newer output, repeating until it’s done. This means a long npm install or build doesn’t hang the conversation — BOR checks back on it.
Background commands
For something you already know is long-running (a dev server, a watcher, a daemon), setbackground="true":
http://localhost:PORT URL) — while leaving the server running. BOR then opens it with browser_action. A dev server started without background="true" would just hit the 60s window.
Killing
The tool only force-kills a command when you pass an explicittimeout_seconds (a kill bound separate from the return window) or the chat is cancelled. The whole process tree is killed (so npm’s children die too). To stop a background process later, BOR runs another command (kill/pkill).
wait_until
read_command_tail). The chat genuinely waits; if you cancel, the wait ends early. In the bubble it shows a countdown card with a progress bar.
This is the companion to the 60-second rule: when a command is still running, wait_until + read_command_tail is how BOR follows it without blocking.
read_command_tail & list_recent_commands
| Tool | Purpose |
|---|---|
read_command_tail | Fetch more output from a prior command by run_id (page through long output, or read what a background command produced after it returned). |
list_recent_commands | List the last 8 commands so BOR can pick a run_id. |
read_command_tail always returns the latest.
Safety
server/validator.js refuses dangerous commands even though a real shell is used: heredocs, host-restart commands (npm run v2, electron, npx bor), and catastrophic patterns (rm -rf /, rm -rf ~, fork bombs, mkfs, dd to a root device, curl | bash). Multi-line inline code (python -c, node -e) is refused — BOR writes a script with write_file and runs that instead.
Use cases
- “Install and run my project.” →
npm install, thennpm run devas a background command, then preview. - “Run my tests.” → run them; if they take >60s,
wait_until+read_command_tailto see the result. - “What’s using port 3000?” →
lsof -i :3000(pipes and all work). - “Convert these images to webp.” → a glob + a CLI, all in one shell command.