Commit Graph
12 Commits
Author SHA1 Message Date
tbenandClaude Opus 5.5 69988e08fc Move secrets between users and computers without the model seeing them
A new personal env scope (paradigm user: one user's secret for one bot)
beats every other scope, reaches only that user's runs of that bot, and
is redacted like any secret. Bots take secrets in with request_secret,
which puts a [secret-request:ID] card in the chat: the user types the
value into a masked input there, never into a message, and the bot is
told only the key. Bots show secrets with capture_secret (a task's
computer tool that saves a file or a command's output straight to a
personal env, then redacts it from the rest of the run) and show_secret
(an env by key): both give a [secret:ID] chip whose Reveal and Copy fetch
the value on click, for its own user (personal) or a super admin
(anything else), logged by key. Values never go into messages, page
props, history, Copy chat or logs. Users manage their own secrets on
Settings > Secrets; the Environment page lists everyone's, remove only.
Deleting a bot or user removes its personal secrets, and SecretsNote
tells bots never to ask for or print secrets in chat.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 16:51:32 +01:00
tbenandClaude Opus 5.5 86becd50bc Keep every bot's computer work in its own workspace folder
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]>
2026-10-25 08:24:49 +01:00
tbenandClaude Opus 5.5 cdb93ac1bc Fix file access, XSS and access-control bugs from a security scan
- Media rows can no longer be created through the CRUD API, updates only
  take description fields on the caller's own row, and every media read
  or delete goes through mediaFilePath, which refuses paths outside
  DATA_DIR or inside the database folder.
- Uploads strip the file name and extension to safe characters and keep
  only title, description and summary from the request's media object.
- Folder imports no longer follow symlinks (walkRegularFiles), and the
  source path is quoted in the computer's shell.
- User and bot files are served with nosniff, and HTML, SVG, XML and
  scripts are sandboxed by CSP.
- Sandbox cookies are kept to the computer's prefix, and websocket
  upgrades on /ws and the computer proxy must come from the app's own
  address (README and Help note nginx's Host header).
- user_types CRUD writes go through the assignment matrix; members only
  read their own user record; read-only users can read CRUD again;
  grabUsers builds valid SQL for array search terms and bad pages; an
  admin media DELETE needs an id; read-only users can't delete media.
- Rate limits and the audit log use the connection's address, trusting
  forwarded headers only from a proxy, and login limits are split per
  address, per account from that address and per account overall.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 03:38:07 +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 f1b7ba535f Stream computer files instead of reading them through the shell
import_file sent a computer's bytes back with base64 over /v1/shell/exec,
whose stdout is capped at 30,047 characters. Every import was therefore
cut at 22,528 bytes and saved anyway, with the tool reporting success: a
1.12 MiB archive became a 22 KB file that would not open, and a crawler's
crawl.json lost half its pages.

The bytes now come from the sandbox's streaming GET /v1/file/download.
The size is read first so nothing over BotFileImportMaxBytes is
transferred, the download asks for change_policy=abort so a file that
changes mid-send is refused rather than half-saved, and the received
length is checked against the size read, so a cut-short transfer fails
loudly. Folders go the same way, as a gzipped tar unpacked into one row
per file.

Bots also name a path as [path:volume:owner:path] now, so what a bot
leaves on a computer is a link into the files browser instead of text.
2026-10-22 07:37:19 +01:00
tbenandClaude Opus 5.5 c44048dbab Add bot schedules (routines), open Activity, add Help and a Desktop computer view
Bots create, list, update and delete schedules (cron_jobs, Bun.cron in UTC);
a per-minute cron queues due runs as tasks. Routines, Activity (super admins)
and Help get their own rail aside. Help covers familiar problems, starting
with signing in to Google through Cookie-Editor over the new Desktop (noVNC)
view.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 10:52:32 +01:00
tbenandClaude Opus 5.5 f24c0d7e82 Run computers with resources and health checks, add settings for bots, workspaces, computers and users
- Computers get CPUs and memory (default 1 CPU, 2 GB), set at creation and
  editable; new resources stop, remove and recreate the container, its home
  dir kept. Every computer container has a docker health check and stays
  "creating" until it passes; only healthy computers are reached, by
  hostname, else by their IP on the network (dev outside docker).
- Docker is required: the app creates the cobble network on startup and
  exits without docker.
- Production container: deploy/run-app-container.sh mounts .env, the data
  dir and the docker socket; the database (DB_DIR), media, computers' homes
  and bun-sqlite's live schema now live on the data volume.
- Settings pages for bots, workspaces, computers and users, sharing list
  components; bots can be deleted; users are created with a password and
  confirmation, edited and deleted through RBAC-gated APIs.
- User types trimmed to super_admin, admin, member, read_only and revoked;
  admins manage members. UserAvatar shows profile photos from the user row.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 10:26:44 +01:00
tbenandClaude Opus 5.5 0ce61cdb49 Add workspaces, conversation sessions, app-managed computers and pictures
- 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]>
2026-10-19 08:39:33 +01:00
tbenandClaude Opus 5.5 56daf0c462 Open computers from the chat, let bots ask for a take-over, show task progress
- 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]>
2026-10-19 05:35:44 +01:00
tbenandClaude Opus 5.5 7b580d782e Add computer switching, crew reporting, job steps and markdown chat
- 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]>
2026-10-19 04:44:35 +01:00
tbenandClaude Opus 5.5 6a2665dae9 Add the harness, envs, per-bot models and chat attachments
- 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]>
2026-10-19 03:38:38 +01:00