Bots can now show a concept as a visual: create_graphic (with
update_graphic, read_graphic and list_graphics, on every run, no computer
needed) stores one HTML document in bot_graphics, per user like the
conversation, and the chat renders its [graphic:ID] ref as an inline card
sized to fit, with a large view and a page of its own (no rail).
Graphic HTML is treated as hostile: it is only served at /graphics/<id>
with a CSP sandbox allowing scripts under an origin of its own and no
network, loading only the vendored Chart.js and Mermaid from
/graphics-lib/. The document carries the app's theme vars and scrollbars,
reports its height to the thread, and a frame that navigates away is
closed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Knowledgebases give bots RAG over documents, scoped like extensions: to
particular bots, to a workspace, or to every bot, with their own button
beside Tools in the composer. Documents are chunked and embedded by the
file-ingest worker with the install's embedding model, which is now an
install-wide setting rather than a per-bot one.
- Word search runs on an FTS5 index ranked by BM25, with a scored LIKE
fallback for scripts written without spaces.
- Changing the embedding model re-indexes documents automatically.
- Ingest jobs wait without spending attempts while every embedding model
rests, fail at once on errors retrying can't fix, and keep passages
searchable by words when the model refuses.
- Settings > Knowledgebases shows each knowledgebase's and document's
index state: spinner, warning, grey check (words only) or green check.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Each computer's Chrome profile now lives on the data volume
(DATA_DIR/computer-browsers/<id>, mounted at ~/.cobble-browser) and
Chrome is pointed at it with --user-data-dir. The sandbox image resets
its own profile's preferences to session-only cookies on every boot,
which signed every site out whenever Chrome exited. New profiles are
seeded with the image's preferences minus that rule, stale Singleton
links are removed before each provision, and existing computers are
recreated once (skipped while a job runs on them).
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]>
- 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]>
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.
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.
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]>