Coordinator and worker come from bots.kind; bot_types now only holds
workspace_admin (was admin), each row naming its workspace, with no scope
field. Rows from v0.2.8 and earlier are fixed at boot by migrateBotTypes.
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]>
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.
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`.
- 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 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]>
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]>