The thinking row and the header menu both carry Stop while a bot has work
open for the user anywhere: every pending or processing job of that bot in
their conversations is failed as stopped, its task closed, a Stopped step
recorded and one closing message posted per session, so the thread stops
waiting and the bot goes idle. The handler running the job is aborted from
this process through a registry, so a job stuck waiting on a model stops at
once instead of on its next heartbeat, and a late face change after the
abort is dropped.
The release stage is now said in the app too: Settings > General reports
"Cobble v0.1.5 (alpha)" next to development, and the README and RELEASING.md
say what alpha means for installs.
Bot and workspace lists in page props leave out instructions, memory and
workspace context, and carry the last message as a short preview. The
header avatar's edit form loads the bot's instructions when it opens.
The conversation renders its latest 30 messages and loads older ones as
the thread scrolls to its top.
Also: the composer shows a placeholder until its editor loads, and
`bun start` no longer builds first.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The composer now puts the bubble and clears the input as soon as you send, so a slow connection never holds either. The bot's status row reads "<name> is getting your message..." until the saved message arrives (by response or push), then switches to thinking. A failed send removes the bubble and restores the text and files.
- Cache the model catalog once per user and each conversation's setting
separately; clear both on logout and after model saves
- Compress hashed assets asynchronously with a byte budget and set Vary
- Memoize message parsing and throttle selection reads
- Debounce draft writes to localStorage
- Keep the composer editor on the page and focused, as before
- Add a bundle budget check and run it in CI
- Show a loading block while sessions load and a workspace avatar in the
mobile conversation header
- Compress responses: page scripts and styles once (brotli or gzip, in
memory) and cached immutable; pages and API JSON gzipped as they stream
- Service worker serves content-named assets cache-first
- Load the models modal's data when it opens (cached in localStorage)
instead of shipping the model catalog in every conversation page
- Lazy-load the Tiptap composer and memoize thread messages
- Import lucide icons directly; twui 0.1.4 drops by-name icons from Button
- bun run start builds the pages minified before serving
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The composer now writes markdown with bold, italic, strike, code,
links, quotes and lists, from shortcuts, markdown typing or a bubble
over the selection. @ mentions a bot and # a workspace, shown as chips
and saved as [bot:ID] / [workspace:ID]. Text selected in a message can
be quoted into the composer. User messages render as markdown, and
replies tell the bot who and what the user mentioned.
Adds an ESM stand-in for use-sync-external-store, since bunext keeps
React external in page bundles and the CommonJS original requires it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Every message has a row under it to reply or react. Replying quotes the
message above the composer, and the sent message stores
reply_to_message_id (a plain id, not a foreign key, so deleting the
quoted message only drops the quote). send-message accepts a quote from
any session of the same conversation, so a rollover or a thread that
moved on still sends; the conversation drops a picked quote when its
session changes. The bot reads the quote as "[Replying to ...]" before
the user's turn, file-only replies included, and relayed messages carry
it too.
Reactions are a fixed set (BotMessageReactions) in
bot_message_reactions, one per message, emoji and user or bot. Users
toggle their own through api/admin/bots/react-message, and every bot
gets react_to_message for the session it answers (the user's latest
message by default). Both push the fresh list as server:bot-reaction,
with mine worked out for the session's user.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- A mic in the composer records, transcribes with the bot's
transcription model (api/admin/bots/transcribe) and writes the text
into the input at the cursor to edit before sending. Escape cancels;
recordings aren't stored.
- Every bot message has a read-aloud button that plays
GET api/admin/bots/speak-message, streamed from the provider as the
audio is made, so it starts in a couple of seconds. One message plays
at a time; only the user's own sessions can be read.
- Both buttons stay visible but disabled while the bot has no model for
them (bot_voice page prop).
- Transcription and speech no longer pick free models automatically:
they're not available until a model is picked, and Settings says so.
Transcription lists speech-to-text models only, so the chat-model
transcript path and its missing-audio check are gone.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A reply that works through tools now shows its latest tool step under
"is thinking…" (not its closing note, which is the answer). While a reply
is due, the open conversation checks the session's latest messages every
few seconds (api/admin/bots/session-messages) and replays any it missed
as server:bot-message, so the thread, rail and unread all take it and the
thinking row can't stay up until a reload. MCP and custom tool steps read
in words ("Using Exa search (web search exa)").
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Bots and workspaces get tools and MCP servers from their settings
pages; bots also from chips under the chat composer, removable there
- "Every bot" now gives one to every bot now and every new bot; each can
still drop it (attach-every-bot-extensions.ts moves old installs over)
- Status lines: MCP servers record whether they connect, tools whether
their last run worked
- Test connection in the MCP form and a Test panel in the tool form check
the form as it is, without saving
- Hide Google sign-in on the login form
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Bots, workspaces and computers now belong to the install. Users reach
workers only through bot_users (assigned by a super admin or admin) and
workspace_users; the coordinator and main computer are one per install,
and only the super admin sees the coordinator. Conversations are per
user (bot_sessions.user_id), jobs run for the session's user, and live
updates go only to who should see them.
A bot's core memory is now general knowledge shared by every user it
works for; what it learns about a user lives in bot_user_memories.
One-off scripts move existing installs over: move-bot-memory-to-owners
(run first), then share-crew.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Rail: Add icon with stacked form modals (bot, workspace, computer),
coordinator, recent bots with "See all bots", Workspaces section, and
a workspace mode listing only its crew
- Workspaces: page for context, bots (per-workspace instructions and
memory), computers (default, link, unlink), models and delete;
conversations scoped per bot per workspace
- Sessions: conversations split into searchable, reopenable sessions
with carry-over summaries; sessions and new-session header icons
- Computers: created and provisioned over the docker socket, home dir
kept at DATA_DIR/computers/<id> after delete; super admins only
- Models: workspace settings win over a bot's own, then the defaults
- Pictures for bots and workspaces; bots editable from the header
- Coordinator tools: update_workspace, set_bot_workspace_instructions
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Serve each computer to its owner under /computers/<id>/ (HTTP and
websockets proxied to the AIO sandbox) and show it in a shared
ComputerView with browser, terminal and code modes, opened from the
computers modal or a take-over button in the thread.
- ask_user_to_take_over lets a bot hand a computer to the user for a
login or captcha; the message gets a take-over button and needs-you,
and the viewer hands it back with a chat message.
- While a task runs the thread shows "<bot> is working..." with the
task's latest step; steps read as plain words, not tool names.
- A coordinator with no workers no longer claims to delegate, and bots
describe started tasks in the first person.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Drop the working-on panel. Rail rows show the bot's status line first.
The header's computer and model controls are ghost icons opening modals
that explain them, and the bot's text model, provider and computer show
under its name. The thread and composer are held to 760px.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Bots have a current computer (bots.computer_id), switched from the chat
header beside the model button or by clicking a computer the bot names
([computer:ID]); tasks run on it by default
- search_computers runs one read-only command on all of a bot's computers;
chat replies know their computers (compose-computers-note)
- The coordinator can use every computer and grants or revokes crew access
with assign_computer
- Delegated jobs record requested_by_bot_id; the worker's result or failure
is reported back in the coordinator's conversation
- bots_queue_updates records each model turn of a job, pushed live and shown
in the working-on panel
- Live relay: every process pushes new messages, job steps and bot changes
from the database to its own sockets, so work done elsewhere shows live
- Bot messages render as markdown (react-markdown + remark-gfm, no raw HTML)
with twui components; rail previews are plain text
- Fix header button overflow in the model and computer selects
- Bump @moduletrace/twui to 0.1.2
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Harness: providers, model catalog synced hourly, automatic free picks,
cooldowns, tool loop with context trimming, MCP computer tools
- Bots queue runs replies and tasks through the harness; jobs wait
(attempt refunded) while every model is resting
- Envs: Settings > Environment, scoped general/workspace/computer,
written to computers and redacted from tool output
- Models: Settings > Models, per-harness provider select defaulting to
OpenRouter, and a models modal on each bot's chat (the coordinator's
edits the defaults)
- Chat: thinking row while a reply runs, file attachments (upload,
paste, drop) that replies read as images, audio and document text
- Fix media uploads failing after a user's first file, and private
files being served from the public media path
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Remove the preset document suite (letters, emails, invoices, quotes,
PDF generation, line items) with its routes, API handlers and tables
- Rebrand to Cobble: site data, Lato, handoff design tokens (light and
dark) in main.css, brand assets in public/brand, ember stone logo and
regenerated favicons
- Add bots, bot_messages, bot_tasks and bot_task_steps tables, regenerate
DB types (BUN_SQLITE_COBBLE_*) and add a sample crew seed (seed:bots)
- Add the chat shell at /admin/bots: rail with pinned coordinator and
user popover, bottom-anchored conversation with composer, working-on
panel, and a send-message API scoped to the session user
- Add BotStone and Wordmark components, crew status and relative time
utils with tests, and update AGENTS.md
Co-Authored-By: Claude Opus 5.5 <[email protected]>