delegate_task takes a task_id to hand over a task already on a list: it
moves to the worker (a workspace's task stays on its list), goes to
doing, and the job is linked back so its end is noted on the task.
hand_over_schedule moves a bot's own routine to another bot, keeping its
workspace. Users get Hand over in the Tasks UI and both routine lists.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A bot's powers came from bots.kind alone, so only the coordinator could
hand work to other bots. bot_types now works like user_types: a row with
no workspace holds everywhere (the coordinator), one with a workspace
only there (a workspace admin), and no row is a worker. bots.kind stays
the legacy marker of the one coordinator for who sees it.
The matrices in src/dict/bot-types-dict.ts say what each type may do,
whom it may direct and who grants it, read by one generic interpreter
(rbac/type-assignment.ts) that userTypeAssignment now wraps too. Every
run reads its powers once (grabBotRunPowers) and the chat tools, task
runs and task tools gate on them instead of kind; a run's powers are its
type's and its user's together.
In the workspace it leads, an admin hands tasks to the workers there
(results relayed back to it), sets their instructions, adds tasks to
their lists and keeps the workspace's context when its user may. Super
admins and admins grant it from the workspace's settings or the chat
header's menu, and the coordinator with set_bot_type. Admins are marked
with a filled green shield beside their name across the workspace, kept
live by pushBotUpdated's admin_workspace_ids.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Computers now mount only /home/gem/workspace from DATA_DIR/computers/<id>,
so only the workspace persists and goes into the data archive. An older
computer's whole home is moved aside to <id>-home-<ts> (kept, never
archived) and its container recreated once by sync-computers.
Each run works in bots/<bot>/users/<user> (also its cwd and HOME), with
bots/<bot> for work every user shares and workspaces/<id> shared by a
workspace's bots; the coordinator reaches the whole workspace. Computer
tools are gated by withComputerDirs: bash and code start there, file tool
paths and file: URLs outside the run's folders are refused, and so is sudo.
search_computers, import_file and script tools start there too.
The files browser shows members only the bots' folders they reach, their
own user folder in each and their workspaces', with names on the id folders.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- Coordinator tools in its own chat (super admin only): list_extensions,
set_extension_access, delete_extension, and update_skill /
update_mcp_server / update_custom_tool for what can't change where
anything is sent (on/off, names, arguments, left-out tools)
- Adding a skill, MCP server or tool, or changing a skill's words, a
server's URL or headers or a tool's kind or config, goes through
propose_skill / propose_mcp_server / propose_custom_tool: stored in
extension_proposals with the bot's background check, shown as a
[proposal:ID] chip that opens a card with Confirm and Reject
- The card's facts are worked out by the app from what Confirm saves: the
host, every {{env.KEY}} and whether it's saved, the config; for a skill
its links, hosts, tool names, mentions of secrets and a diff against
the saved runbook
- Confirming decides once and checks again; a server or tool missing a key
is saved switched off, and the outcome is posted to the bot in chat
- Never from a bot: stdio servers, a URL whose host a template decides,
envs in a prompt tool, a key's value
Co-Authored-By: Claude Opus 5.5 <[email protected]>
delegate_task had no workspace argument: a task handed over from the
coordinator's own chat always ran in the worker's own chat, on that
worker's memory, files and directly assigned computers alone, even when
the work belonged to a workspace. The coordinator could not say where the
work goes, and the prompt never said the two differ.
- delegate_task takes an optional workspace_id: the worker runs the task
in that workspace's context, with its own instructions and memory
there, the project's files and the workspace's computers, and the
result lands in its conversation in that workspace.
- A worker missing from that workspace is added first (pushBotCreated)
and the reply says so.
- Handed over from inside a workspace the task always runs there; a
different workspace_id is refused instead of ignored.
- The coordinator prompt, CoordinatorReplyNote and the tool description
now spell the distinction out.
A coordinator asked to set an uploaded logo as a workspace picture could
not: the picture tools take a media id, and nothing ever gave the bot one.
Attachments reached the model as "[Attached image \"logo.png\"]", every
file tool answers with a [file:ID] ref, and an SVG is deliberately stored
as a document rather than an image.
- copyMediaAsPicture copies an approved image into a new picture row
(bot-image/workspace-image). The source keeps its row and bytes, so a
message that attached it still loads and changing a picture can never
take a file away from a conversation.
- grabPictureSource resolves a picture by [file:ID] (the same scope gate
every file tool uses) or by the user's own upload; parseFileRef reads
the [file:12] form.
- The new set_picture tool ships on every run: a bot sets its own face,
the coordinator can also dress a worker. update_workspace gained
picture_file_id, and setBotPicture/setProfileImage share the copy and
the delete.
- removeReplacedPicture deletes a replaced picture only when it really is
one, never a chat upload.
- uploadAndRecordMedia writes images in their own format: PNG stays PNG
with its transparency, WebP stays WebP, GIF becomes PNG, everything
else JPEG, and the row records the real mime type (it used to say jpeg
for every image).
- Pictures change live: BotUpdatedData carries image_media_id and a new
server:workspace-updated pushes workspace pictures, relayed between
processes.
- Attachments are labelled with their media id, and BotFilesNote tells a
bot that a [file:ID] can become a picture.
- grabRunScopes is now the single source of a run's reachable folders,
shared by the file tools, imports and the picture tools.
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.
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.
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]>
- 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.
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.
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.
The coordinator had no tool to add a worker, so a request to create one
fell back to update_workspace and wrote a bot that did not exist into the
workspace context. create_bot now adds a worker with its name, role and
instructions and joins it to a workspace, and add_bot_to_workspace puts an
existing worker in one. Both are coordinator-only and chat-replies-only,
and createBot still enforces the crew-manager check.
The coordinator's prompts now say how a bot gets created, and that one
which does not exist is never written into workspace context.
pick-free-hue moves to utils so the tool can pick a hue without importing
from layouts.
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]>
- 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]>