Add a chat list and server-minted new chats on top of the desk API's
GET/POST /desk/chats:
- server_client.list_chats() / create_chat(), same shape and error
handling as list_outbox_files().
- Switching is config.set_session(id): a plain reassignment of the
SESSION_ID every call reads, persisted to session.json. The window
refuses to switch mid-turn rather than locking.
- gui/chat_list_window.py: a Chats dialog (Ctrl+K) with a QListWidget,
populated on open, with Refresh and New Chat. Network calls run as
QRunnables on the global QThreadPool and come back through Signals,
never from a slot. The header New chat (Ctrl+N) uses the same path.
- Switching clears the local transcript; there is no endpoint for a
past chat's messages. Bolt's memory is per user, so it carries over.
- Terminal: /chats, /chat <n|id>, and /new (server-minted id, local
fallback).
This commit also carries the uncommitted work since 54030a7 that turned
this Bolt-Pet fork into Bolt Console: the pet, wake word, TTS and screen
features removed; a Claude Code-style terminal client; the PySide6
window with tool cards, approvals and diffs; mic dictation through the
server's /desk/stt relay; filectl/JSON repairs; and detection of
invented tool results.
Build output (build/, dist/, Release/, *.spec) is now ignored.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
5.8 KiB
Bolt Console
A desktop app for Bolt, in the style of Claude Code (with a terminal version too). You type, Bolt answers, and when he needs to look at or change something on this machine you see each step as it happens: reading files, listing folders, editing, writing, running commands. Changes wait for your Allow on the step itself, and edits show a diff first.
It talks to the same Bolt server as Bolt-Pet, the Discord bot and the phone app, so it has the same brain, memory, tools and persona. What it drops is the desktop pet around it: no sprite, no wake word, no microphone, no speech, no screen reading.
The window is PySide6 with its own dark theme. Header: working folder (click to change) and an Ask first / Auto switch. Below that: the conversation, with each tool call as a card that you can click to expand, and a composer at the bottom (Enter sends, Shift+Enter adds a new line, Ctrl+L clears, Ctrl+O picks a folder).
Chats (Ctrl+K) lists every conversation you've had with Bolt, from any device (console, pet,
phone), newest first. Open one to continue it. New chat (Ctrl+N, or the button in the Chats
dialog) asks the server for a fresh chat: new conversation history, but Bolt still remembers you,
because his memory belongs to you, not to a chat. Switching clears the window's transcript, since
the server has no endpoint for an old chat's messages, although Bolt still has them. The current
chat is remembered across restarts. The terminal version has /chats, /chat <n> and /new.
Dictation: the mic button next to Send (or Ctrl+M) records you and types what you say into the box
as you talk. Click again or pause for 3 seconds to stop, and Esc cancels. The text isn't sent until you
press Enter, so you can fix it first. It uses the same speech-to-text as Bolt-Pet: the Bolt server's
/desk/stt relay to Deepgram, so you don't need a Deepgram account. The server does count it against
your credits like a chat turn. MIC_DEVICE in .env picks the microphone.
The terminal version (run-cli.bat / ./run.sh --cli) looks like this:
> what's taking up space in this repo?
● List(C:\work\site, recursive)
⎿ assets/
assets/hero.mp4 48211332B
... +212 lines
● Shell(du -sh assets/* | sort -h | tail -5)
Run this command? [y]es / [n]o / [a]lways this session y
⎿ 48M assets/hero.mp4
...
● Most of it is one file: assets/hero.mp4 at 48 MB. ...
Setup
cp .env.example .env # set BOLT_SERVER_URL and DESK_API_KEY
run.bat # Windows: the window
run-cli.bat # Windows: the terminal version
./run.sh [--cli] # macOS/Linux
The launchers create .venv on first run. Dependencies: requests, plus PySide6 for the window
(the terminal version doesn't import Qt). Bolt works in the
directory you launch from, so you can put the launcher on your PATH and start it inside whatever
project you want him to work on.
run.bat --auto # don't ask before commands, writes and edits
run-cli.bat -p "summarise README.md" # one message, print the reply, exit
run-cli.bat --doctor [--deep] # check the install (--deep contacts the server)
Using the terminal version
| Input | What it does |
|---|---|
| any text | sent to Bolt |
!<command> |
runs a shell command yourself. Nothing is sent to Bolt |
/cd <dir>, /pwd |
change or show the working directory |
/ask, /auto |
turn approval prompts on or off for this session |
/status |
server, session, approval mode, working directory |
/files |
download anything Bolt has queued for you |
/new |
start a fresh chat (same as New chat in the window) |
/chats, /chat <n> |
list your chats from every device; switch to number n (or a session id) |
/clear |
clear the screen. Bolt's memory lives on the server and is kept |
/help, /exit |
|
line ending in \ |
keep typing on the next line |
Ctrl+C stops the spinner and gives the prompt back. The server may still finish that turn on its side. At an approval prompt, Ctrl+C means no.
How Bolt reaches this machine
The desk API has one tool channel: the server sends back a command string, the client runs it and
posts the output to /desk/tool_result, and this repeats until a final reply. The console decides
what each string means (bolt_console/tools.py):
filectl {json}: list, read, write or edit a file (file_ops.py). This is what makes file editing reliable, because the model never has to hand-quote a shell heredoc. Edits must match exactly once. Common JSON slips, such as a rawC:\Users\...path, are repaired and the model is told about the repair.petctl …/dialoguectl …: the pet's body and voice. These are not run. Bolt is told there's no pet here.- anything else: a real shell command, run in the working directory, with a
COMMAND_TIMEOUT_SECONDSlimit (default 120s).
Reads and listings never ask. Shell commands, writes and edits ask first in ask mode (the
default). Edits show a diff before you answer.
Security
Anything you approve runs as your user, with your permissions. In auto mode that means anything
the server asks for. Keep DESK_API_KEY private and don't expose the desk API to the open internet.
Each message includes your working directory and OS name (CONSOLE_CONTEXT=false to stop that).
Development
QT_QPA_PLATFORM=offscreen .venv/bin/pytest tests/ # Windows: .venv\Scripts\pytest tests
tests/test_gui.py drives turns through the real window and its worker thread against the same
loopback server.
tests/test_console.py runs whole turns against a real HTTP server on a loopback port. Only the
keyboard is faked. Everything else takes its collaborators as arguments, so no test needs a real
terminal or server.
This project started as a copy of Bolt-Pet. See that repo for the voice/desktop-pet version.