Commit Graph
165 Commits
Author SHA1 Message Date
tben e859bab294 Serve HTTPS by default with a local CA
The installer generates a CA and a 397-day certificate into
$COBBLE_HOME/certs (in the app image, with the host's addresses), mounts
the certificate, key and CA into the container and serves TLS from Bun on
the published port. --no-https opts out; --https-cert/--https-key use a
real certificate, --https-host adds names and --https-regen replaces the
CA. The installer and the image health check use curl -k when TLS is on.

The CA is served at /ca.crt and as an iOS/macOS profile at
/ca.mobileconfig for one-tap install. Development picks up certs/
automatically, `bun run dev:phone` generates and starts, and a plain-HTTP
listener on PORT + 1 redirects to HTTPS. Port sharing is off, so a stale
dev server fails instead of silently answering on the same port.
2026-10-20 10:20:01 +01:00
tbenandClaude Opus 5.5 535adb6e16 Make routines act on their own and check every bot action
Scheduled runs are pre-approved: they carry out their brief instead of
drafting for confirmation. A run that can't do its brief calls
report_run_failed and is retried 5 and 10 minutes later; only then does
the user get one "failed after N tries" message, and the routine keeps
why in last_error.

Every reply and task now gets ActionCheckNote: look for an existing
record before creating one, and verify an action took effect before
saying it's done. Memory and instructions saves are read back, and
create_bot, create_schedule, start_task and delegate_task refuse
duplicates.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 08:45:49 +01:00
tben 6c57fae444 Use short install URL in installer and docs 2026-10-20 08:35:36 +01:00
tben e73eab3d41 Require the current container init setting on update
CI / check (push) Canceled after 0s
2026-10-20 07:45:06 +01:00
tben f20f20f8a2 Document the release and launch checklist
CI / check (push) Canceled after 0s
2026-10-20 07:43:55 +01:00
tben 2b2c41bebd Check the image architecture before starting
CI / check (push) Canceled after 0s
2026-10-20 07:34:16 +01:00
tben d0798a93a5 Add the self-hosted installer and release workflows
CI / check (push) Canceled after 0s
2026-10-20 07:02:58 +01:00
tbenandClaude Opus 5.5 1208eac6b7 Replace the composer textarea with a Tiptap markdown editor
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]>
2026-10-20 05:48:23 +01:00
tben e2093b0df6 Update frontend UI/UX 2026-10-20 04:59:08 +01:00
tben 59f5acb7bc Update bot chat block 2026-10-19 22:09:02 +01:00
tbenandClaude Opus 5.5 100ef0eb89 Only offer reply and reactions on bot messages
The user's own messages no longer get the reply and react row. A bot's
reaction to one still shows, read-only, and react-message refuses a
reaction on the user's own message.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 22:04:29 +01:00
tbenandClaude Opus 5.5 d1b5b6d68a Add replies and emoji reactions to chat messages
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]>
2026-10-19 21:56:31 +01:00
tbenandClaude Opus 5.5 bc499a7466 Let admins hear a voice sample before picking it
The Speech section of every model settings form now has "Hear a
sample", which streams a short sentence (AppData.VoicePreviewText) in
the form's model and voice before they're saved, through
GET api/admin/harness/preview-voice (super admins and admins, that
model only via grabModelCandidate). pickVoice is shared with
speakText, and explainAudioError reads why a streamed player failed
for both read-aloud and the sample.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 21:32:49 +01:00
tbenandClaude Opus 5.5 148d02dcfe Show a bot group's time beside the last message's play button
The timestamp no longer takes its own line under a bot group: it sits
before the read-aloud button on the last message, after the needs-you
chip when there is one.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 21:23:53 +01:00
tbenandClaude Opus 5.5 163d9a434c Add dictation and streamed read-aloud to the chat
- 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]>
2026-10-19 21:21:04 +01:00
tbenandClaude Opus 5.5 727cbf53c8 Let the composer grow with long prompts and focus from anywhere on its row
The input row had a fixed 88px height, so a growing textarea overflowed
into the thread and tools strip. It now has a minimum height, grows to
eight lines then scrolls, keeps the buttons at the bottom, and falls back
to a JS auto-grow where field-sizing isn't supported. A click anywhere on
the row focuses the input.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 20:42:13 +01:00
tbenandClaude Opus 5.5 bf7109952b Link existing bots from the workspace rail's "+"
The "+" beside "Workspace bots" now opens a modal listing the crew's
workers not in the workspace yet (api/admin/workspaces/linkable-bots),
each added in one click, with "New bot" stacking the bot form over it.
Adding a bot to a workspace now pushes server:bot-created so other
rails pick it up live.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 20:37:25 +01:00
tben 139b3e443d Give the coordinator working crew management tools
- Resolve the crew and workspaces fresh inside each tool run, so a bot or
  workspace created earlier in the same reply is usable: create_bot,
  assign_computer, add_bot_to_workspace, delegate_task and
  set_bot_workspace_instructions.
- Add coordinator-only update_bot, find_bot, find_workspace, delete_bot,
  delete_workspace and remove_bot_from_workspace tools.
- Push server:workspace-removed when a workspace is deleted, and
  workspace_ids on server:bot-updated so a workspace's crew drops a bot
  that was taken out of it.
2026-10-19 20:34:51 +01:00
tben b79cebf397 Cap rail bot and workspace lists at five with see-all summary 2026-10-19 20:11:04 +01:00
tben b0c9c84b2b Give workspace computers to attached bots in their own chat
A computer linked to a workspace now shows in the composer (and is usable
by tasks and replies) when chatting with any bot attached to that
workspace, not only in the workspace conversation. Members see those
computers through their assigned workers too, and assign_computer still
describes direct grants only.
2026-10-19 20:03:38 +01:00
tben f57b464e80 Use a smaller spinner on rail session rows 2026-10-19 18:39:56 +01:00
tben 0aad723a50 Group the rail's open bot with its sessions
The active row and its session previews now share one highlighted card,
with a hairline thread from the bot's icon down to the last session.
2026-10-19 18:33:46 +01:00
tben 4d5195447b Name sessions with the model and keep the rail list live
Sessions no longer take their title from the first message: once the first exchange is sent, the text model writes the title and summary, which the rail and sessions list show. The summary records how many messages it covers so a stale one is rewritten before it is carried into the next session.

The sessions hook now reloads on live message and session events, so a session started by the first message, a rollover or another tab appears without a reload. New sessions are pushed as server:bot-session, both from the process that changed them and through the live relay.
2026-10-19 18:05:57 +01:00
tben 9293a55032 Remove the closed people pages, keep their user form in settings 2026-10-19 17:43:07 +01:00
tben b9488623fc Give the sessions modal more room on wide screens 2026-10-19 17:37:08 +01:00
tben b390306166 Move backups into the settings pages
Admin settings gains a super-admin Backups page at
/admin/settings/backups, with restore nested at .../backups/restore.
Both use SettingsShell and SettingsGroup like the other settings sub
pages instead of the retired admin hero.
2026-10-19 17:37:03 +01:00
tben 53cf054d70 List the open bot's recent sessions in the rail
Show the latest five sessions under the active bot, with All sessions opening the existing modal once there are more. Share the session modal, row and hook outside the conversation page, and mark the current session with a muted row.
2026-10-19 17:27:57 +01:00
tben dbfe48796b Make the app an installable PWA with phone layout and Web Push
Add a generated manifest, icon set, offline page and service worker that never caches authenticated HTML, plus install and update UI. Turn the rail into a drawer below md with container-query internals, dvh and safe-area handling, and reconnect the socket after visibility/network changes. Add Web Push subscriptions, presence-aware delivery, notification settings and tests.
2026-10-19 17:12:16 +01:00
tbenandClaude Opus 5.5 61098a114c Show a reply's steps, and catch up on a reply whose live push was missed
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]>
2026-10-19 16:28:53 +01:00
tbenandClaude Opus 5.5 425ae723cf Put the composer's computer button after the Add tool chip
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:28:53 +01:00
tbenandClaude Opus 5.5 4ee81d6127 Let a bot answer its sessions side by side, and show a due reply in each
Replies were locked per bot, so a long reply in one session held up every
other session's reply with nothing shown. The lock is now per session. A
chat shows the thinking row whenever the user has the last word, rather
than from the bot's face (one per user, shared by every session), so it
shows even while the bot works elsewhere. A task waiting for its busy
computer says so, and a job finishing while another still runs puts back
the running one's face.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:09:21 +01:00
tbenandClaude Opus 5.5 e157863cfb Label the composer's computer button and move it after the tools
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 16:09:21 +01:00
tbenandClaude Opus 5.5 9b55ef793b Keep the rail's back link on one line, truncated with an ellipsis
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 15:54:53 +01:00
tbenandClaude Opus 5.5 a207f9ae93 Open the bot's computer from beside the composer's tools
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 15:52:43 +01:00
tbenandClaude Opus 5.5 dd1e9e0cfe Let members view a workspace's dashboard, editing still for managers only
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 15:48:23 +01:00
tbenandClaude Opus 5.5 391943a1c2 Set a user's bots and workspaces in their own groups, saved at once
Take the Bots and Workspaces pickers out of the user form. A user's
settings page lists what they reach in two groups, like a workspace's
Bots group: each row links to its settings and can be taken away, and
a select adds one, saved straight away through users/add-access and
users/remove-access (setUserGrant).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 15:44:59 +01:00
tbenandClaude Opus 5.5 6294b911e6 Give bots tools and MCP servers per bot and workspace, with status and tests
- 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]>
2026-10-19 15:35:13 +01:00
tbenandClaude Opus 5.5 c6ec7d77a2 Add MCP servers and custom tools for bots
Two new settings pages, MCPs and Tools. Super admins define them; super
admins and admins attach them to bots, to workspaces (every bot there),
or to every bot. Bots get them in chat replies and tasks.

- Custom tools: a JSON-schema of arguments plus an HTTP request, a script
  on the bot's computer, or a prompt, templated with {{args.x}} and
  {{env.KEY}}, secrets redacted from results.
- MCP servers: remote (URL and headers) or stdio commands run on the host
  with a setup command and an isolated env, in a per-process pool. Tools
  are listed into a cache and connect on first call.
- Add, edit, access and try open in modals.
- Markdown, JSON and command fields use twui's AceEditor (CodeEditor),
  its scripts loaded on demand.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 15:01:39 +01:00
tben 550aaeabac Let the coordinator create workspaces and write findings in tasks
create_workspace gives the coordinator a way to start a workspace with its shared context, and the tool list is shared, so a new id can be used by create_bot or add_bot_to_workspace in the same reply.

A coordinator's tasks now get create_workspace and update_workspace too: the research task that had the material could only report it, never write it into the workspace, so the coordinator promised an update it had no turn to make.

A workspace created from chat is pushed as server:workspace-created, from the tool and from the live relay, so the rail shows it without a reload.
2026-10-19 14:32:47 +01:00
tbenandClaude Opus 5.5 1cafb40eef Pick a bot's colour from stone tiles instead of a select
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 14:20:12 +01:00
tbenandClaude Opus 5.5 6c1399f88f Keep composer drafts across reloads and preview attached images
The composer's unsent text and uploaded files are kept in localStorage
per bot and workspace until sent. Picked images show a small preview in
place of their icon.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 14:18:13 +01:00
tbenandClaude Opus 5.5 e7a7f56ec7 Make bots proactive about the next step
Every bot now offers one concrete next step after answering in chat and
ends task reports with a suggested follow-up. The coordinator proposes
what comes next when a worker's report comes back.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 14:06:47 +01:00
tbenandClaude Opus 5.5 ab25158d87 Give every user their own bot face
A bot's face and status line live in bot_user_faces, one row per bot and
user, set by jobs for the user whose conversation they're in. Needs-you
and working only show to that user; every bot read overlays the viewer's
face (botFaceSql) and pushes go to the user a face change is for.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 13:58:26 +01:00
tben 47c58bc76b Reuse computer rows and open computers in the viewer 2026-10-19 13:50:04 +01:00
tben e5747effa8 Make a workspace page a dashboard and drop its coordinator from the rail
The workspace rail now lists only the bots attached to the workspace, with the back link returning to the workspace page from a bot's conversation. /admin/workspaces/<id> becomes a read-only dashboard (picture, context, latest activity, bots, computers) that links into the editable settings page.
2026-10-19 13:40:59 +01:00
tben 7b1ccfeb62 Add computer settings pages and restore workspace pages 2026-10-19 13:30:02 +01:00
tben 7667f2bc2f Add dedicated bot, workspace and user settings pages 2026-10-19 13:17:17 +01:00
tben 731ea73486 Take a deleted bot out of the rail at once
Deleting a bot only changed the page after a reload. The delete route now
reads who could see the bot before removing it, since its assignments and
workspace places go with it, then pushes server:bot-removed
(BotRemovedData) to them. useLiveBots drops the row, so every tab and
every workspace the bot was in updates together.
2026-10-19 12:20:38 +01:00
tben fccaa6e280 Show a newly created bot in the rail at once
The rail was built from page props and only knew bots it already had, so a
bot the coordinator created did not appear until a reload.

create_bot and add_bot_to_workspace now push server:bot-created
(BotCreatedData) to everyone who sees the bot: its rail row, the
workspaces it is in, and whether it belongs in that user's own chat list.
useLiveBots inserts it, after the pinned coordinator outside a workspace
and only when the open workspace is one it joined. liveRelay pushes created
bots too, so a bot added by another process still shows.
2026-10-19 12:17:56 +01:00
tben c1cb313bd0 Focus the composer when a conversation opens
Typing starts right away instead of needing a click in the box first.
2026-10-19 12:11:07 +01:00