68 Commits
Author SHA1 Message Date
tben 63a93a4262 Keep only the bot cookie for the last visited bot
CI / check (push) Canceled after 0s
A workspace conversation is never remembered, so /admin/bots always
reopens the bot's own chat.
2026-10-22 13:39:36 +01:00
tben 08d02e6033 Give bots skills: runbooks they load when a job matches
A skill is a runbook: a name, a unique slug, a one-line description of when
it applies, and the markdown body. A run only ever sees the slug and
description (one load_skill tool carries them), and reads the whole body
only when it calls the tool, so a long runbook costs nothing until needed.

Skills are the third extension kind beside MCP servers and custom tools, on
the same botExtensionsSql path, so per-bot, per-workspace and all-bots
grants work the same way, and attachDefaultExtensions hands an every-bot
skill to new bots. load_skill is a reserved tool name, so a custom tool
cannot shadow it, and a built-in wins a clash.

Managed on Settings > Skills; ExtensionRow links each kind to its own page
and a skill never reports a failure, since nothing connects or runs.
2026-10-22 12:31:42 +01:00
tben 1a6249afd3 Let a bot take any colour
A bot's identity was one of seven hues, and the hue picked both its colour
and its stone shape. Now its colour is free and its stone is its own:

- `bots.color` holds any `#rrggbb`, `bots.stone` the flat-cut shape it's
  drawn on. `bots.hue` stays as the palette column they replaced, read only
  as a fallback; `src/scripts/move-bot-colour-to-owners.ts` backfills an
  install from it (safe to rerun).
- `src/utils/bot-color.ts` is the only place a colour is validated or
  resolved (`resolveBotColor`/`resolveBotStone` carry the old hue forward,
  `botColorNeedsPaperFace` flips the eyes to paper on a very dark body), and
  `src/utils/bot-stone-props.ts` gives every row its props, so a row saved
  before this still renders as it did.
- `BotStone` takes the colour as the body's SVG `fill`, the one documented
  exception to the token rule: an arbitrary hex has no token to point at.
  `UnreadDot` follows it.
- The picker keeps the palette tiles (still shape and colour together) and
  adds a native swatch and a hex field, so a custom colour keeps its stone.
  Same place as before: the header avatar's modal and Settings > Bots, for
  crew managers. The coordinator stays hue-less.
- A recolour reaches other open tabs through `pushBotUpdated`.
2026-10-22 11:55:36 +01:00
tben 16f1e7904a Open the bot last visited, else the coordinator
`/admin/bots` sent the super admin to the coordinator and everyone else to
their latest bot, which lost the thread each time the tab was reopened. The
conversation pages now record where the browser is in two HttpOnly cookies
(`cobble_last_visited_bot_id`, `..._workspace_id`, a year, `Secure` only over
HTTPS), and the landing page opens that conversation again, in its workspace
when it was one.

A stale cookie can't loop: `grabReachableConversation` re-checks it with
`grabUserConversation`, the gate the conversation pages use, so a revoked
grant, a deleted bot or an archived workspace falls back to the coordinator
(super admin) or the latest bot, first workspace, empty page. Signing out
clears both cookies so the next user on that browser doesn't land in the
previous one's conversation.
2026-10-22 11:18:19 +01:00
tben a8d8b680ad Append install-wide instructions to every bot's prompt
Settings > General gains a prompt appendix the super admin sets once:
markdown every bot runs with, right after its own core instructions.

- The text lives in app_settings (bot_system_prompt_append, read through
  grabSystemPromptAppend, cached like every app setting), so it changes
  without a deploy and applies to every bot on the next run.
- composeBotPrompt takes an appendix and pushes it as
  # Install-wide instructions directly after system_prompt, before the
  workspace block and memory, so the bot's own more specific rules still
  win. grabBotPrompt feeds it in, so chat replies, tasks, scheduled runs
  and the coordinator all get it with no call site touched.
- api/admin/settings/system-prompt-append saves it (super admin only,
  capped at AppData.PromptMaxLength, empty clears it) and is audit
  logged under system.
- The section and its form are hidden from everyone but the super admin,
  save in place with a character count and no reload, and say what an
  empty text does.
2026-10-22 11:12:38 +01:00
tben a88898d169 Archive the whole data volume in Backups, not just the database
Settings > Backups gains a whole-data archive beside the database
snapshots, and both lists now fully work from the page.

- Data archives: `write-data-backup-archive.ts` tars all of DATA_DIR into
  BACKUP_ARCHIVE_DIR as cobble-data-<epoch-ms>.tar.gz, every entry under one
  root folder named after the archive, writing a .part name and renaming on
  success so a cut-off run is never listed. The newest
  AppData.DataBackupsKept are kept; db/.backups is left as it is.
- Restore: `restore-data-backup.ts` extracts to a temp dir, requires one
  root folder holding a db folder, takes a safety archive first, then
  replaces DATA_DIR (the database snapshots included) and `restart-app.ts`
  restarts the process through the docker socket, since the open SQLite
  handle points at the replaced file.
- Upload and restore: a modal over each list (database file or data
  archive), replacing the old /admin/settings/backups/restore page.
- Delete for both kinds, icon-only row actions shared through
  RowIconButton, and restore on every row.
- One backup or restore of either kind at a time (with-backup-run-lock).
- BACKUP_ARCHIVE_DIR is a start-up path (ProcessOnlyEnvKeys); the installer
  mounts $COBBLE_HOME/backups-archives at /backups-archives and recreates a
  container that lacks it. The image installs tar and gzip.
2026-10-22 11:00:37 +01:00
tben aebd6b8ccc Serve every media file privately at /media/<id>
There is no public media any more. `/media/public/<id>` served a media
row with no session at all, so anyone with the id could read a file.
The public/private split is gone: the path is `/media/<id>` (and
`/media/<id>/thumbnail`), every request is signed in first, and
`grabUserMedia` decides whether the user may see it: their own upload,
a bot's or workspace's picture or file they reach, or a file on a task
they reach. Anything else is a 404 before a path is built.

The `media.is_private` column and the two per-user directories went
with it: uploads live in `media/<user_id>/` and there is nothing to
pick between. The files browser's media volume is now the viewer's
own folder whatever their role.

Bots also say which of the two things they mean. A `[file:ID]` ref is a
saved file and its chip opens the bytes; a folder is a new
`[folder:volume:owner:path]` ref (`src/utils/folder-ref.ts`) whose chip
opens the files browser there and downloads nothing. The old `[path:...]`
ref and the extension sniffing that guessed file from folder are gone,
so `import_file` names the folder holding a file it copied rather than
the file itself.

The prompts say what the Assistant got wrong: list before importing or
saving, one copy per artifact, never split a file into parts unless
asked, never claim the store is empty without a fresh list, and never
invent a size cap. A re-import now says the path already existed
instead of silently overwriting and reporting a fresh copy.
2026-10-22 10:10:53 +01:00
tben 96735de48f Let a bot and a workspace set their own envs
Envs had three scopes, general, workspace and computer. A bot had no
scope of its own, so the only way to give one worker a key was to set it
on a computer it happened to share.

The envs table gets a bot_id, and resolution now layers bot over
computer over workspace over general, so a bot's own key wins wherever it
runs. Every computer call site passes the run's bot_id, and grabRunEnvs
does the same for the {{env.KEY}} a custom tool or an MCP server's headers
read.

A bot's and a workspace's settings page can now edit their own envs, in
place, through the same save-env and delete-env routes: sending `scoped`
makes them answer with just that scope instead of the whole install's
overview. Super admins only, like the Environment page.
2026-10-22 08:30:40 +01:00
tben 7a3d2df213 Document the files browser, import streaming and the FK trap
Records why import_file must not read bytes through the shell (its
30,047-character stdout cap truncated every file), why a conversation's
file props have to carry the whole folder tree, and why any helper that
deletes a parent row must delete its children explicitly instead of
trusting the schema's cascade.
2026-10-22 07:37:29 +01:00
tben 7cb26c4e36 Add tasks: the crew's shared to-do list
Bots and workspaces each keep a list of work tracked until it's done, and
the bots move it along themselves as they work.

- tasks (one collection per bot or per workspace), task_notes (the
  progress log) and task_media (a deliverable or a reference file, its
  bytes a private media row served at /media/private/<id>)
- statuses todo/doing/blocked/done/cancelled, with blocked_reason while
  only the user can unblock it
- visibility as SQL in src/utils/task-access: a user's own bots and
  workspaces, a run's own list plus its workspaces, everything for the
  coordinator; every tool and endpoint resolves through it
- list_tasks, create_task and update_task on every run, so a chat reply,
  a task and a routine all read the list, log progress and file what they
  produced
- TasksNote on every run and TaskReminderNote in chat, so a greeting or a
  proposed next step brings pending work up in one measured line
- tasks group on the workspace dashboard and a tasks modal in the
  conversation header, sharing one form, row and detail panel
- a bot's or workspace's own chat uploads are read before the delete so
  none are stranded; bot files keep their folder

Also corrects the README's RAM guidance and table alignment.
2026-10-22 05:57:50 +01:00
tben fe502b38fe Rework the README with current screenshots
The README was a bare file list. It now opens with the horizontal
lockup, a theme-aware hero and a workspace dashboard, both taken from
the running app, so GitHub's preview shows the product instead of
describing it.

AGENTS.md records that the design handoff is outdated: its screens and
briefs are history, while its brand assets (stones, coordinator, app
icon, wordmark) and their copies in src/data are still the foundation.
2026-10-22 04:15:43 +01:00
tben d17a4a7bdd Add bots files handling logic 2026-10-21 17:56:09 +01:00
tben b0af4db1bf Open the composer's tools in a modal behind one counting button
The chips under the composer clogged it once a bot had a handful of MCP servers and tools. They are now one button reading "N tools" (with an alert icon when one is off or not working) that opens them in a modal, where any the bot was given can still be removed and more added.
2026-10-21 16:49:56 +01:00
tben 361b8add9b Run development on the dev server's code, not a build's cache
A production deploy leaves its service worker on the device, and it
claims every tab. It serves /.bunext/public/* cache first without
knowing which build asked, while every cache-busting mechanism the app
has (the precache gate, /build-info.json, the loading page) is
production only. So switching to `bun run dev` kept serving the old
build, vendor files included, and wrote the dev files back into the
production build's cache.

Development now clears that worker and every cache it wrote
(`clear-development-service-worker.ts`, from ServiceWorkerRegistrar,
which did nothing in development before), reloads once into the
uncontrolled tab, and /sw.js answers with a stub that unregisters
itself so Web Push and the loading page can't register it back.
2026-10-21 15:57:29 +01:00
tben 8bf6bedec5 Serve plain HTTP only and drop the local certificate tooling
The app never terminates TLS: a reverse proxy or tunnel does, and
isSecureRequest still reads X-Forwarded-Proto so cookies stay Secure.
Removes the cert generator, TLS resolution and HTTP redirect, the
local CA download, and the TLS envs, and trims the installer, Dockerfile
health check and docs to match. Also softens the composer's loading row.
2026-10-21 15:35:27 +01:00
tbenandClaude Opus 5.5 f13fa863c5 Trim page props and page the conversation's messages
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]>
2026-10-20 20:09:01 +01:00
tbenandClaude Opus 5.5 b3057119df Download the whole app build behind a loading page
In production, a page request without the running build's cookie gets a
small loading page instead of the app. It downloads every file in
.bunext/public (listed at /build-info.json) into that build's cache,
checks they are all there, hands over to a new service worker waiting
behind an older one, sets the cookie and reloads. The service worker
then serves the app's code from the cache, so later visits load it from
the device.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 19:33:15 +01:00
tben 8425631b3a Show sent messages before the server confirms them
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.
2026-10-20 14:50:20 +01:00
tben 4f7e0a6bf0 Finish the mobile performance pass
- 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
2026-10-20 14:37:11 +01:00
tbenandClaude Opus 5.5 c1a94fc9a5 Make pages load fast on mobile
- 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]>
2026-10-20 13:41:45 +01:00
tben 3b355d68bc Keep bot jobs and harness calls from hanging 2026-10-20 12:59:24 +01:00
tben 3e13052a25 Run the bots queue and cron with bun run start 2026-10-20 10:49:44 +01:00
tben 459eebf73d Use the certs/ fallback in every environment
TLS no longer depends on NODE_ENV: the TLS_* variables win, else certs/
is used whenever it exists (the container's /app/certs mount lands there
too), and TLS_DISABLED=1 is the only way to serve plain HTTP with a
certificate present. The plain-HTTP redirect listener now starts whenever
TLS is on, not only in development, and HTTP_REDIRECT_PORT replaces
DEV_HTTP_PORT. The installer writes TLS_DISABLED=1 for --no-https, and the
health check follows the same rule.
2026-10-20 10:29:37 +01:00
tben 8c20c9a7ed Ask about HTTPS on a fresh install
A fresh install asks whether to serve HTTPS, with the reasons, before
touching anything. --yes keeps the default, --no-https answers it, and an
update keeps the saved mode. The prompt reads /dev/tty so `curl | bash`
still works; without a terminal the default is explained instead.

Also state why a production process is serving plain HTTP (no TLS vars),
instead of only giving that hint in development.
2026-10-20 10:24:38 +01:00
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 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
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 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 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 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 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 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 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 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