Markdown rendered, CSV/TSV as a table, images, PDFs, audio, video and
sandboxed HTML in place, other text as code, with Download and Open in a
new tab. Used by file chips, message attachments, the files modal, task
files and the files browser.
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]>
A bot's deliverables and the raw material behind them only existed as
paths in a message, so they couldn't be opened from the app at all. This
browses them read-only at /admin/files, one volume at a time: a bot's own
folder, a workspace's shared one, a computer's home (where a bot's ~/...
actually is), the media library, an MCP server's install folder and the
database.
Access is the whole gate: resolveStorageSpec checks the viewer against
the volume first (a bot through grabUserBot, a workspace through
grabUserWorkspace, a computer through grabUserComputer, media only their
own unless they manage the crew) and no path is built before it passes.
resolveStoragePath then applies the resolveBotPath rules to any root.
The picker lists folders through reachableBotsSql, so it never offers one
the resolver would refuse.
Reading is listStorageEntries (folders first, paginated, symlinks
skipped, catalog rows joined so a bot file still opens through its media
row) and grabStorageFile for bytes under a cap, both behind an ETag.