Changelog

The project should feel alive

Readable release notes from GitHub, designed for humans.

Latest release

v2.12.1

Jul 18, 2026

Grok reaches parity with the other cloud agents, the Cortex knowledge base grows a real management surface, and the mobile knowledge experience is rebuilt for phones.

opendray update
View release
v2.12.1 Current

Release notes

Grok reaches parity with the other cloud agents, the Cortex knowledge base grows a real management surface, and the mobile knowledge experience is rebuilt for phones.

Added

  • Grok is now a first-class cloud agent. It can drive the shared memory MCP (memory search, doc_read, cross-layer recall) just like Claude / Codex / Antigravity — its spawn folder is marked trusted so grok actually starts the injected memory server instead of silently skipping it. Grok and OpenCode are also selectable in Discuss with AI and as Memory Worker agent providers, and creating a grok session now offers the Bypass permissions / YOLO toggle (--always-approve) the other agents already had.
  • A cross-page KB Librarian (experimental). Launch a dedicated agent session — pick its cloud agent, model and account — that can organize, create, edit and delete any global knowledge page across the whole base, driven conversationally, unlike the per-page Discuss chat. It gets read + write KB tools (list / upsert config / write body / delete) on its memory MCP; those tools are scoped to the Librarian session alone and never reach ordinary or third-party sessions.
  • Edit a knowledge page's settings after creation. A kb_* page's title, one-line description, nature (foundational / emergent) and inject flag were locked in at creation; they are now editable in place (web + mobile) on every page except the classic four — including seeded pages like Integrations, so you can flip a page between full-inject and on-demand retrieval.
  • Discuss with AI model lists are live and accurate. Antigravity and OpenCode models are enumerated straight from their CLIs, and Codex offers its full model family (higher plans unlock the fuller models) instead of one pinned choice — no more picking a stale model that fails at spawn.
  • Round Table members can change mid-conversation. Add or remove seated providers on an active chat (web + mobile) — an added member is @mentionable on the next turn with the full thread as context; a removed one stops replying while its past messages stay.
  • Mobile: staged image uploads. Images queue in a dismissable tray before send instead of uploading immediately.

Improved

  • The mobile Knowledge (KB) page is rebuilt as a searchable list → detail flow. The old horizontal page-chip strip didn't scale once you had many kb_* docs; the KB tab is now a grouped, searchable list (Foundational / Emergent) that grows gracefully, and tapping a page opens a full-screen reader/editor with its actions in an AppBar overflow menu. New page and the Librarian move onto a FAB.

Fixed

  • Grok sessions had no MCP / memory tools. opendray wrote the memory server into the project-scoped <cwd>/.grok/config.toml, but grok refuses to start repo-local MCP servers in an untrusted folder as a supply-chain guard, so the server was configured but never started. opendray now trusts the operator's own spawn folder (--trust), matching the other CLIs.
  • The web terminal input cursor no longer drifts on iPad.
View details

Grok reaches parity with the other cloud agents, the Cortex knowledge base grows a real management surface, and the mobile knowledge experience is rebuilt for phones.

Added

  • Grok is now a first-class cloud agent. It can drive the shared memory MCP (memory search, doc_read, cross-layer recall) just like Claude / Codex / Antigravity — its spawn folder is marked trusted so grok actually starts the injected memory server instead of silently skipping it. Grok and OpenCode are also selectable in Discuss with AI and as Memory Worker agent providers, and creating a grok session now offers the Bypass permissions / YOLO toggle (--always-approve) the other agents already had.
  • A cross-page KB Librarian (experimental). Launch a dedicated agent session — pick its cloud agent, model and account — that can organize, create, edit and delete any global knowledge page across the whole base, driven conversationally, unlike the per-page Discuss chat. It gets read + write KB tools (list / upsert config / write body / delete) on its memory MCP; those tools are scoped to the Librarian session alone and never reach ordinary or third-party sessions.
  • Edit a knowledge page's settings after creation. A kb_* page's title, one-line description, nature (foundational / emergent) and inject flag were locked in at creation; they are now editable in place (web + mobile) on every page except the classic four — including seeded pages like Integrations, so you can flip a page between full-inject and on-demand retrieval.
  • Discuss with AI model lists are live and accurate. Antigravity and OpenCode models are enumerated straight from their CLIs, and Codex offers its full model family (higher plans unlock the fuller models) instead of one pinned choice — no more picking a stale model that fails at spawn.
  • Round Table members can change mid-conversation. Add or remove seated providers on an active chat (web + mobile) — an added member is @mentionable on the next turn with the full thread as context; a removed one stops replying while its past messages stay.
  • Mobile: staged image uploads. Images queue in a dismissable tray before send instead of uploading immediately.

Changed

  • The mobile Knowledge (KB) page is rebuilt as a searchable list → detail flow. The old horizontal page-chip strip didn't scale once you had many kb_* docs; the KB tab is now a grouped, searchable list (Foundational / Emergent) that grows gracefully, and tapping a page opens a full-screen reader/editor with its actions in an AppBar overflow menu. New page and the Librarian move onto a FAB.

Fixed

  • Grok sessions had no MCP / memory tools. opendray wrote the memory server into the project-scoped <cwd>/.grok/config.toml, but grok refuses to start repo-local MCP servers in an untrusted folder as a supply-chain guard, so the server was configured but never started. opendray now trusts the operator's own spawn folder (--trust), matching the other CLIs.
  • The web terminal input cursor no longer drifts on iPad.
Open on GitHub
v2.12.0 Stable

Release notes

Added Round Table — a cross vendor AI group chat (experimental). Seat several providers (Claude / Codex / Antigravity / Grok / OpenCode) plus the operator in one shared thread; @mention who should reply (or @all) and eac

Added

  • Round Table — a cross-vendor AI group chat (experimental). Seat several providers (Claude / Codex / Antigravity / Grok / OpenCode) plus the operator in one shared thread; @mention who should reply (or @all) and each member answers in character after reading the whole conversation, so heterogeneous foundation-model families react to each other in seat order. Summarize the discussion on demand, or turn it into a role-assigned execution plan — each step runs as a real session in a shared project (bind the project after the fact if you started without one). Hand the whole thread off to a working session to do the actual code changes. A chat can be closed and reopened (close keeps the thread, just stops new messages). Available on both the web admin and the mobile app — where Round Table gets its own bottom-nav tab, per-agent bubble colours, and labelled action menus. Fully self-contained and rollback-able (internal/roundtable/ROLLBACK.md).

Fixed

  • The Files-tree download icon is now reachable on touch devices (iPad, phones). The per-row download button was revealed only on hover (group-hover) or keyboard focus. Tailwind v4 gates group-hover behind @media (hover: hover), so on a touch device — which can neither hover nor focus a row — the icon stayed at opacity-0 and was impossible to tap. It now pins visible under @media (hover: none), so touch users get a permanently-shown download control while pointer users keep the clean hover-reveal. (Follow-up to the v2.11.6 positioning fix, which addressed where the icon sits but not whether it ever appears without a mouse.)
  • Two MCP servers sharing a display name no longer brick Codex sessions. Every provider renderer keys its generated config on a server's display name, not its unique id. Two enabled servers with the same name therefore collided on that key: Codex emitted a duplicate [mcp_servers."…"] TOML table and died with duplicate key at startup — before printing a byte, so the session flipped straight to the read-only "[buffer unavailable]" view — while Claude's map-based renderer silently dropped one of them. renderMCP now rejects a duplicate name up front (for every provider, before any config file is written), and the Plugins create/update endpoints return 409 when a new or edited server would reuse a name already taken by a different id. Grok's manifest gap and this collision are unrelated; a stray second Notion entry sharing the name Notion API is what exposed it.
  • Grok now reports and applies CLI updates from the Providers page. The grok manifest carried an empty npmPackage, and the whole update path is npm-gated: CheckUpdate returned early (no latest version, no "update available" flag) and Update hard-errored with "not updatable via npm". Grok is published as @xai-official/grok (maintainer [email protected]), so the manifest now names it.
  • A provider CLI installed outside npm can now be updated in place. Grok's documented installer (curl -fsSL https://x.ai/cli/install.sh | bash) drops a symlink into the npm bin dir that npm does not own, and npm refuses to clobber it — EEXIST: file already exists. Simply naming the package would therefore have shipped a dashboard that advertises an update behind a button that always fails. Update now preflights the bin path: an unmanaged symlink is cleared so npm can take ownership (and the update output tells the operator exactly which link was replaced), while a regular file is never deleted — it is reported instead, mirroring the existing ErrUpdatePrefixReadonly preflight. Grok's install note now recommends npm install -g @xai-official/grok.
View details

Added

  • Round Table — a cross-vendor AI group chat (experimental). Seat several providers (Claude / Codex / Antigravity / Grok / OpenCode) plus the operator in one shared thread; @mention who should reply (or @all) and each member answers in character after reading the whole conversation, so heterogeneous foundation-model families react to each other in seat order. Summarize the discussion on demand, or turn it into a role-assigned execution plan — each step runs as a real session in a shared project (bind the project after the fact if you started without one). Hand the whole thread off to a working session to do the actual code changes. A chat can be closed and reopened (close keeps the thread, just stops new messages). Available on both the web admin and the mobile app — where Round Table gets its own bottom-nav tab, per-agent bubble colours, and labelled action menus. Fully self-contained and rollback-able (internal/roundtable/ROLLBACK.md).

Fixed

  • The Files-tree download icon is now reachable on touch devices (iPad, phones). The per-row download button was revealed only on hover (group-hover) or keyboard focus. Tailwind v4 gates group-hover behind @media (hover: hover), so on a touch device — which can neither hover nor focus a row — the icon stayed at opacity-0 and was impossible to tap. It now pins visible under @media (hover: none), so touch users get a permanently-shown download control while pointer users keep the clean hover-reveal. (Follow-up to the v2.11.6 positioning fix, which addressed where the icon sits but not whether it ever appears without a mouse.)
  • Two MCP servers sharing a display name no longer brick Codex sessions. Every provider renderer keys its generated config on a server's display name, not its unique id. Two enabled servers with the same name therefore collided on that key: Codex emitted a duplicate [mcp_servers."…"] TOML table and died with duplicate key at startup — before printing a byte, so the session flipped straight to the read-only "[buffer unavailable]" view — while Claude's map-based renderer silently dropped one of them. renderMCP now rejects a duplicate name up front (for every provider, before any config file is written), and the Plugins create/update endpoints return 409 when a new or edited server would reuse a name already taken by a different id. Grok's manifest gap and this collision are unrelated; a stray second Notion entry sharing the name Notion API is what exposed it.
  • Grok now reports and applies CLI updates from the Providers page. The grok manifest carried an empty npmPackage, and the whole update path is npm-gated: CheckUpdate returned early (no latest version, no "update available" flag) and Update hard-errored with "not updatable via npm". Grok is published as @xai-official/grok (maintainer [email protected]), so the manifest now names it.
  • A provider CLI installed outside npm can now be updated in place. Grok's documented installer (curl -fsSL https://x.ai/cli/install.sh | bash) drops a symlink into the npm bin dir that npm does not own, and npm refuses to clobber it — EEXIST: file already exists. Simply naming the package would therefore have shipped a dashboard that advertises an update behind a button that always fails. Update now preflights the bin path: an unmanaged symlink is cleared so npm can take ownership (and the update output tells the operator exactly which link was replaced), while a regular file is never deleted — it is reported instead, mirroring the existing ErrUpdatePrefixReadonly preflight. Grok's install note now recommends npm install -g @xai-official/grok.
Open on GitHub
v2.11.6 Patch

Release notes

Fixed The download icon is reachable again in a deep or long file tree. The session inspector's Files tree renders inside a scroll area whose inner wrapper sizes to its content, so long filenames and deep nesting pushed

Fixed

  • The download icon is reachable again in a deep or long file tree. The session inspector's Files tree renders inside a scroll area whose inner wrapper sizes to its content, so long filenames and deep nesting pushed rows wider than the panel: names were hard-cut with no ellipsis, and the hover-download icon — anchored to each row's right edge — sat beyond the visible edge, so hovering a file appeared to do nothing. The tree is now constrained to the panel width, so names truncate with an ellipsis and the download icon sits at the visible right edge. The Database tab is unaffected (its grid scrolls in its own containers). (#443)
View details

Fixed

  • The download icon is reachable again in a deep or long file tree. The session inspector's Files tree renders inside a scroll area whose inner wrapper sizes to its content, so long filenames and deep nesting pushed rows wider than the panel: names were hard-cut with no ellipsis, and the hover-download icon — anchored to each row's right edge — sat beyond the visible edge, so hovering a file appeared to do nothing. The tree is now constrained to the panel width, so names truncate with an ellipsis and the download icon sits at the visible right edge. The Database tab is unaffected (its grid scrolls in its own containers). (#443)
Open on GitHub
v2.11.5 Patch

Release notes

Added TUIs follow the opendray theme. A terminal UI picks a light/dark palette by asking the terminal — via the OSC 11 background query (which xterm.js already answered) or the COLORFGBG environment variable, which opendray never set.

Added

  • TUIs follow the opendray theme. A terminal UI picks a light/dark palette by asking the terminal — via the OSC 11 background query (which xterm.js already answered) or the COLORFGBG environment variable, which opendray never set. So a CLI that reads the environment (Grok's theme = "auto", vim, tmux, …) had no way to know the operator was in light mode and always defaulted to dark. opendray now stamps the client's applied theme on session create and advertises it at spawn via COLORFGBG. Optional and backward-compatible: no theme advertises nothing and the CLI keeps its own default, and an explicit COLORFGBG already in the environment still wins. (#446)
  • The mouse wheel scrolls full-screen TUIs. In the alternate screen there is no xterm scrollback, and a CLI that hasn't grabbed the mouse never receives wheel events either — so the wheel silently did nothing and a Grok conversation couldn't be scrolled at all. opendray now does what a real terminal does (alternate-scroll): wheel notches become cursor Up/Down keys when the app is in the alternate screen and hasn't grabbed the mouse. CLIs that do grab the mouse (Claude Code, Codex, Antigravity) are unaffected — they already receive the wheel as SGR events. (#446)
  • Custom tasks are pre-scoped to the current project. (#442)

Fixed

  • A disconnected browser no longer wedges CLI updates. Provider updates ran npm install -g on the HTTP request context, so a client disconnect (browser closed, proxy timeout) cancelled it and SIGKILLed npm mid-install. A half-killed npm leaves a partial global tree behind — a stale .<pkg>-XXXXXX temp dir — after which every later install fails with ENOTEMPTY, permanently wedging updates for that CLI (a codex update stayed broken for a week this way, and left a CLI whose platform binary never landed, so its sessions failed too). The install is now detached from the caller's cancellation. (#445)
  • A broken CLI is now visible instead of looking healthy. When a provider's binary is on PATH but won't run, opendray used to fall back to showing the manifest version — rendering a CLI that can't even launch as perfectly fine. It now reports "Installed but not runnable" with the CLI's own error, and a failed update surfaces npm's actual message (ENOTEMPTY: …) rather than a bare exit status 217. (#445)
View details

Added

  • TUIs follow the opendray theme. A terminal UI picks a light/dark palette by asking the terminal — via the OSC 11 background query (which xterm.js already answered) or the COLORFGBG environment variable, which opendray never set. So a CLI that reads the environment (Grok's theme = "auto", vim, tmux, …) had no way to know the operator was in light mode and always defaulted to dark. opendray now stamps the client's applied theme on session create and advertises it at spawn via COLORFGBG. Optional and backward-compatible: no theme advertises nothing and the CLI keeps its own default, and an explicit COLORFGBG already in the environment still wins. (#446)
  • The mouse wheel scrolls full-screen TUIs. In the alternate screen there is no xterm scrollback, and a CLI that hasn't grabbed the mouse never receives wheel events either — so the wheel silently did nothing and a Grok conversation couldn't be scrolled at all. opendray now does what a real terminal does (alternate-scroll): wheel notches become cursor Up/Down keys when the app is in the alternate screen and hasn't grabbed the mouse. CLIs that do grab the mouse (Claude Code, Codex, Antigravity) are unaffected — they already receive the wheel as SGR events. (#446)
  • Custom tasks are pre-scoped to the current project. (#442)

Fixed

  • A disconnected browser no longer wedges CLI updates. Provider updates ran npm install -g on the HTTP request context, so a client disconnect (browser closed, proxy timeout) cancelled it and SIGKILLed npm mid-install. A half-killed npm leaves a partial global tree behind — a stale .<pkg>-XXXXXX temp dir — after which every later install fails with ENOTEMPTY, permanently wedging updates for that CLI (a codex update stayed broken for a week this way, and left a CLI whose platform binary never landed, so its sessions failed too). The install is now detached from the caller's cancellation. (#445)
  • A broken CLI is now visible instead of looking healthy. When a provider's binary is on PATH but won't run, opendray used to fall back to showing the manifest version — rendering a CLI that can't even launch as perfectly fine. It now reports "Installed but not runnable" with the CLI's own error, and a failed update surfaces npm's actual message (ENOTEMPTY: …) rather than a bare exit status 217. (#445)
Open on GitHub
v2.11.4 Patch

Release notes

Added Mobile: Resources section + Updates "what's new" sheet. The mobile app gains the sidebar Resources block and the Updates/"what's new" sheet, reaching parity with the web admin (#433).

Added

  • Mobile: Resources section + Updates "what's new" sheet. The mobile app gains the sidebar Resources block and the Updates/"what's new" sheet, reaching parity with the web admin (#433). (#439)

Fixed

  • Antigravity spawns no longer fail on an empty MCP config. antigravity's first-run migration writes an empty ~/.gemini/config/mcp_config.json; opendray's MCP-injection prep parsed it unconditionally and errored with "provider prepare: parse …/mcp_config.json … unexpected end of JSON input", blocking every Antigravity session spawn. An empty (or whitespace-only) file is now treated as "no config yet" rather than a parse error, on both the mcp_config.json and gemini settings.json surfaces. (#440)
  • Grok provider icon. Grok is now registered in the web provider icon/visual lookup tables so its brand mark renders. (#434)
View details

Added

  • Mobile: Resources section + Updates "what's new" sheet. The mobile app gains the sidebar Resources block and the Updates/"what's new" sheet, reaching parity with the web admin (#433). (#439)

Fixed

  • Antigravity spawns no longer fail on an empty MCP config. antigravity's first-run migration writes an empty ~/.gemini/config/mcp_config.json; opendray's MCP-injection prep parsed it unconditionally and errored with "provider prepare: parse …/mcp_config.json … unexpected end of JSON input", blocking every Antigravity session spawn. An empty (or whitespace-only) file is now treated as "no config yet" rather than a parse error, on both the mcp_config.json and gemini settings.json surfaces. (#440)
  • Grok provider icon. Grok is now registered in the web provider icon/visual lookup tables so its brand mark renders. (#434)
Open on GitHub
v2.11.3 Patch

Release notes

Added Session terminal: staged image attachments. Uploading an image to a session (attach button, clipboard paste, or drag and drop) now stages it as a dismissable chip in a tray at the bottom of the terminal instead of

Added

  • Session terminal: staged image attachments. Uploading an image to a session (attach button, clipboard paste, or drag-and-drop) now stages it as a dismissable chip in a tray at the bottom of the terminal instead of typing the server path straight into the running CLI. Esc (or the chip's ✕) cancels it — an empty tray still passes Esc through to the CLI — and an Insert button commits the path(s) when you're ready. Fixes the long-standing "the uploaded path can't be dismissed" surprise. Web for now; mobile parity to follow. (#436)
  • Sidebar Resources block + Updates drawer. The web admin's left nav gains a Resources section under Settings: an Updates drawer that shows "what's new" from GitHub Releases (falling back to CHANGELOG.md) with an unread badge and "mark read", plus Docs, Community, and Sponsor links. (#433)
View details

Added

  • Session terminal: staged image attachments. Uploading an image to a session (attach button, clipboard paste, or drag-and-drop) now stages it as a dismissable chip in a tray at the bottom of the terminal instead of typing the server path straight into the running CLI. Esc (or the chip's ✕) cancels it — an empty tray still passes Esc through to the CLI — and an Insert button commits the path(s) when you're ready. Fixes the long-standing "the uploaded path can't be dismissed" surprise. Web for now; mobile parity to follow. (#436)
  • Sidebar Resources block + Updates drawer. The web admin's left nav gains a Resources section under Settings: an Updates drawer that shows "what's new" from GitHub Releases (falling back to CHANGELOG.md) with an unread badge and "mark read", plus Docs, Community, and Sponsor links. (#433)
Open on GitHub
v2.11.2 Patch

Release notes

Added Database tool — MySQL, MariaDB and SQLite. The Database tool now connects to MySQL and MariaDB (host/port/username like PostgreSQL; a MySQL "schema" is a database) and SQLite in addition to PostgreSQL.

Added

  • Database tool — MySQL, MariaDB and SQLite. The Database tool now connects to MySQL and MariaDB (host/port/username like PostgreSQL; a MySQL "schema" is a database) and SQLite in addition to PostgreSQL. The connection form (web and mobile) gains an engine picker with per-engine default ports. SQLite is a file-path connection: the path is fenced to the connection's project cwd (a path escaping it via ../ or a symlink is rejected) and extension loading is disabled. Reads run behind the same read-only fence on every engine (SQLite via a dedicated read-only connection pool). All engines are pure-Go drivers (go-sql-driver/mysql, modernc.org/sqlite), so the binary still cross-compiles without cgo. Migration 0075 widens the driver constraint; 0076 reseeds the kb_integrations page.

Fixed

  • Backup download link authorises correctly. The backup download URL now carries the admin token, so downloading a backup from the web UI no longer fails auth. (#428)
View details

Added

  • Database tool — MySQL, MariaDB and SQLite. The Database tool now connects to MySQL and MariaDB (host/port/username like PostgreSQL; a MySQL "schema" is a database) and SQLite in addition to PostgreSQL. The connection form (web and mobile) gains an engine picker with per-engine default ports. SQLite is a file-path connection: the path is fenced to the connection's project cwd (a path escaping it via ../ or a symlink is rejected) and extension loading is disabled. Reads run behind the same read-only fence on every engine (SQLite via a dedicated read-only connection pool). All engines are pure-Go drivers (go-sql-driver/mysql, modernc.org/sqlite), so the binary still cross-compiles without cgo. Migration 0075 widens the driver constraint; 0076 reseeds the kb_integrations page.

Fixed

  • Backup download link authorises correctly. The backup download URL now carries the admin token, so downloading a backup from the web UI no longer fails auth. (#428)
Open on GitHub
v2.11.1 Patch

Release notes

Added Mobile parity — Database tool in the session inspector. The mobile app's session inspector gains a Database tab mirroring the web tool: browse schemas and tables, page through rows, insert / update / delete by prim

Added

  • Mobile parity — Database tool in the session inspector. The mobile app's session inspector gains a Database tab mirroring the web tool: browse schemas and tables, page through rows, insert / update / delete by primary key, and run read or write SQL against the project's registered connections — honouring db:read / db:write scopes and read-only connections, and reusing the session's cwd for isolation.
  • Mobile parity — upload files into a session. The mobile session inspector's Files tab gains an upload button: pick one or more files and stream them into the current directory via POST /api/v1/fs/upload, matching the web files-sidebar upload shipped in v2.11.0 (same resolveWithinRoot sandbox, auto-rename on name collision).

Security

  • Database tool — cryptographic per-project isolation for the auto-attached MCP. The opendray-dbtool MCP now holds a db:signed key and sends a per-session X-OpenDray-Dbtool-Sig = HMAC(secret, cwd) header; the gateway rejects a signed-key call whose signature doesn't match the cwd. An agent that extracts the injected key can no longer forge another project's cwd — closing the residual the honest-path check left open. Antigravity (whose MCP config is HOME-global and can't carry a per-session signature — a Google limitation) and third-party integration keys keep the plain ?cwd= check via a separate honest-path key. Migration 0074 reseeds the kb_integrations page.

Fixed

  • Database tool — bigint primary keys stay exact. Row update/delete and filters decode JSON with UseNumber, so a 64-bit primary key above 2^53 is no longer rounded through float64 (which could address the wrong row or match none). Numbers beyond int64 keep their exact string.
  • Database tool — consistent table metadata. TableMeta runs its four catalog queries (columns / PK / indexes / FKs) inside one read-only transaction, so concurrent DDL can't produce a half-updated view.

Improved

  • Dependencies. Bump golang.org/x/crypto 0.50.0 → 0.52.0 (#421) and golang.org/x/net 0.52.0 → 0.55.0 (#418), pulling transitive x/sys and x/text updates. Build and vet clean.
View details

Added

  • Mobile parity — Database tool in the session inspector. The mobile app's session inspector gains a Database tab mirroring the web tool: browse schemas and tables, page through rows, insert / update / delete by primary key, and run read or write SQL against the project's registered connections — honouring db:read / db:write scopes and read-only connections, and reusing the session's cwd for isolation.
  • Mobile parity — upload files into a session. The mobile session inspector's Files tab gains an upload button: pick one or more files and stream them into the current directory via POST /api/v1/fs/upload, matching the web files-sidebar upload shipped in v2.11.0 (same resolveWithinRoot sandbox, auto-rename on name collision).

Security

  • Database tool — cryptographic per-project isolation for the auto-attached MCP. The opendray-dbtool MCP now holds a db:signed key and sends a per-session X-OpenDray-Dbtool-Sig = HMAC(secret, cwd) header; the gateway rejects a signed-key call whose signature doesn't match the cwd. An agent that extracts the injected key can no longer forge another project's cwd — closing the residual the honest-path check left open. Antigravity (whose MCP config is HOME-global and can't carry a per-session signature — a Google limitation) and third-party integration keys keep the plain ?cwd= check via a separate honest-path key. Migration 0074 reseeds the kb_integrations page.

Fixed

  • Database tool — bigint primary keys stay exact. Row update/delete and filters decode JSON with UseNumber, so a 64-bit primary key above 2^53 is no longer rounded through float64 (which could address the wrong row or match none). Numbers beyond int64 keep their exact string.
  • Database tool — consistent table metadata. TableMeta runs its four catalog queries (columns / PK / indexes / FKs) inside one read-only transaction, so concurrent DDL can't produce a half-updated view.

Changed

  • Dependencies. Bump golang.org/x/crypto 0.50.0 → 0.52.0 (#421) and golang.org/x/net 0.52.0 → 0.55.0 (#418), pulling transitive x/sys and x/text updates. Build and vet clean.
Open on GitHub
v2.11.0 Stable

Release notes

Added Upload files & folders into a session from the files sidebar. The session inspector's files panel can now create folders and upload files or whole folders (recursively, preserving the subtree) via an upload button

Added

  • Upload files & folders into a session from the files sidebar. The session inspector's files panel can now create folders and upload files or whole folders (recursively, preserving the subtree) via an upload button or drag-and-drop — including dropping onto a specific folder row to target it, or the panel background to target the session cwd. Uploads land in the session's working directory where the AI model reads them, streamed to disk (250 MiB per file) and confined to the session cwd by the same resolveWithinRoot sandbox the download/zip endpoints use — path traversal and symlinked-intermediate escapes are rejected. Conflicting names auto-rename (name-1.ext) instead of overwriting what the session produced. New admin-only endpoint POST /api/v1/fs/upload on the existing /fs group; the tree refreshes to show new files (including renames). (#420)
  • Database tool — direct project database access. opendray can now hold per-project (cwd-keyed) database connections and expose them like a JetBrains-style database tool: browse schemas/tables, read table data, edit rows, and run a SQL console. It surfaces two ways — a Database tab on each project screen (web: connection manager, lazy schema tree, paginated data grid with row insert/edit/delete, and a CodeMirror SQL console with schema-aware autocompletion; mobile: connection management, schema browse, read-only query) and an auto-attached opendray-dbtool MCP server (db_connections_list / db_schema / db_table_data / db_query / db_execute) so agent sessions can query and mutate a project's database directly. PostgreSQL only for now (a driver interface reserves MySQL/SQLite). Connection passwords are encrypted at rest with the same field cipher as channel/git-host secrets and are never returned by any read endpoint. Two new scopes — db:read (browse + read-only SQL) and db:write (row CRUD + write/DDL) — gate integration access; registering a connection stays admin-only (an integration can never point opendray at a new host). Reads run inside a server-side READ ONLY transaction with a statement timeout, and per-connection read_only refuses every write regardless of scope. The dbtool MCP is withheld from origin=integration sessions, matching memory isolation. Configurable via [dbtool] (enabled by default; the feature is inert until a connection is registered). Migrations 0072 (schema) and 0073 (kb_integrations reseed).
  • Mobile: antigravity multi-account parity with web. The mobile app gains the antigravity multi-account management already shipped on web (#396). (#409)
  • Mobile: Grok provider brand mark, syncing the real Grok icon added to web in #405. (#408)
  • Memory search surfaces folded (deduped) variants in memory_search and memory_load_context, so callers see the merged form rather than near-duplicate rows. (#414)

Fixed

  • antigravity MCP injection now targets the real config surface, so injected servers actually reach antigravity sessions. (#416)
  • Transcript overlay for CLIs with unscrollable TUIs — the web terminal can surface scrollback for tools whose full-screen TUI can't be scrolled natively. (#415)
  • project_search moved from admin-only to dual-auth + memory:read scope, so integrations can search project memory. (#413)
  • Per-provider spawn parity — codex bypass, antigravity memory CLI, and a default-model guard for integration-originated sessions. (#412)
  • Integration default-agent model is an explicit dropdown rather than a free-text datalist, on both web (#411) and mobile (#410).

Docs

  • README refresh — reworked hero, added comparison + FAQ, and synced the 5-CLI provider list across all 10 translations. (#417)
View details

Added

  • Upload files & folders into a session from the files sidebar. The session inspector's files panel can now create folders and upload files or whole folders (recursively, preserving the subtree) via an upload button or drag-and-drop — including dropping onto a specific folder row to target it, or the panel background to target the session cwd. Uploads land in the session's working directory where the AI model reads them, streamed to disk (250 MiB per file) and confined to the session cwd by the same resolveWithinRoot sandbox the download/zip endpoints use — path traversal and symlinked-intermediate escapes are rejected. Conflicting names auto-rename (name-1.ext) instead of overwriting what the session produced. New admin-only endpoint POST /api/v1/fs/upload on the existing /fs group; the tree refreshes to show new files (including renames). (#420)
  • Database tool — direct project database access. opendray can now hold per-project (cwd-keyed) database connections and expose them like a JetBrains-style database tool: browse schemas/tables, read table data, edit rows, and run a SQL console. It surfaces two ways — a Database tab on each project screen (web: connection manager, lazy schema tree, paginated data grid with row insert/edit/delete, and a CodeMirror SQL console with schema-aware autocompletion; mobile: connection management, schema browse, read-only query) and an auto-attached opendray-dbtool MCP server (db_connections_list / db_schema / db_table_data / db_query / db_execute) so agent sessions can query and mutate a project's database directly. PostgreSQL only for now (a driver interface reserves MySQL/SQLite). Connection passwords are encrypted at rest with the same field cipher as channel/git-host secrets and are never returned by any read endpoint. Two new scopes — db:read (browse + read-only SQL) and db:write (row CRUD + write/DDL) — gate integration access; registering a connection stays admin-only (an integration can never point opendray at a new host). Reads run inside a server-side READ ONLY transaction with a statement timeout, and per-connection read_only refuses every write regardless of scope. The dbtool MCP is withheld from origin=integration sessions, matching memory isolation. Configurable via [dbtool] (enabled by default; the feature is inert until a connection is registered). Migrations 0072 (schema) and 0073 (kb_integrations reseed).
  • Mobile: antigravity multi-account parity with web. The mobile app gains the antigravity multi-account management already shipped on web (#396). (#409)
  • Mobile: Grok provider brand mark, syncing the real Grok icon added to web in #405. (#408)
  • Memory search surfaces folded (deduped) variants in memory_search and memory_load_context, so callers see the merged form rather than near-duplicate rows. (#414)

Fixed

  • antigravity MCP injection now targets the real config surface, so injected servers actually reach antigravity sessions. (#416)
  • Transcript overlay for CLIs with unscrollable TUIs — the web terminal can surface scrollback for tools whose full-screen TUI can't be scrolled natively. (#415)
  • project_search moved from admin-only to dual-auth + memory:read scope, so integrations can search project memory. (#413)
  • Per-provider spawn parity — codex bypass, antigravity memory CLI, and a default-model guard for integration-originated sessions. (#412)
  • Integration default-agent model is an explicit dropdown rather than a free-text datalist, on both web (#411) and mobile (#410).

Docs

  • README refresh — reworked hero, added comparison + FAQ, and synced the 5-CLI provider list across all 10 translations. (#417)
Open on GitHub
v2.10.1 Patch

Release notes

Added MCP servers reach Grok. Grok Build sessions now receive opendray's enabled MCP registry (HashiCorp Vault, etc.), per provider mcp servers, integration scoped servers, and the opendray memory server — the same injec

Added

  • MCP servers reach Grok. Grok Build sessions now receive opendray's enabled MCP registry (HashiCorp Vault, etc.), per-provider mcp_servers, integration-scoped servers, and the opendray-memory server — the same injection every other MCP-capable provider gets. opendray writes them into the project-scoped <cwd>/.grok/config.toml [mcp_servers] table, which Grok union-merges with your global ~/.grok/config.toml (your personal servers are untouched). Previously Grok shipped with MCP injection disabled, so it could not see Vault or any other shared server the operator had configured. (#404)
  • Cortex-first knowledge framing. The spawn banner now opens with a preamble telling the agent to consult opendray's injected cortex (kb_* pages) as the authoritative source first, treating any external mirror (Obsidian vault, wiki) as a secondary fallback used only when the cortex doesn't cover the topic. Stops agents from grounding infra/DB process answers in stale external notes when the curated copy is already in-context. (#406)
  • Current objective always injected. Lean-mode spawns now inject the live current_objective body as a dedicated "work to THIS" block (not just an index entry the agent had to remember to fetch), plus a stronger proactive-maintenance directive so agents keep current_objective, the journal, and durable memory current on their own. (#403)
  • On-demand, section-level KB access. doc_read and project_search can now pull a single heading-section of a large global knowledge page instead of the whole thing — a kb_integrations lookup drops from ~15K tokens to ~300–1.3K, and search hits carry a doc_read(slug, section=…) pointer instead of dead-ending on a teaser. (#400)
  • Cross-project distilled knowledge now applies. Fixed the experience compiler reading session outcomes through an ephemeral table, which starved it of feedstock (112 journal summaries → only 2 survived) so it produced zero global playbooks. Outcomes are now denormalized onto the durable journal row (migration 0070, with a one-shot backfill of historical rows), so the compiler sees the full corpus and its global playbooks auto-inject at spawn. (#402)

Fixed

  • Grok provider icon. Grok now shows its real brand mark in the spawn dialog and provider rail instead of the neutral letter-disc fallback. (#405)
View details

Added

  • MCP servers reach Grok. Grok Build sessions now receive opendray's enabled MCP registry (HashiCorp Vault, etc.), per-provider mcp_servers, integration-scoped servers, and the opendray-memory server — the same injection every other MCP-capable provider gets. opendray writes them into the project-scoped <cwd>/.grok/config.toml [mcp_servers] table, which Grok union-merges with your global ~/.grok/config.toml (your personal servers are untouched). Previously Grok shipped with MCP injection disabled, so it could not see Vault or any other shared server the operator had configured. (#404)
  • Cortex-first knowledge framing. The spawn banner now opens with a preamble telling the agent to consult opendray's injected cortex (kb_* pages) as the authoritative source first, treating any external mirror (Obsidian vault, wiki) as a secondary fallback used only when the cortex doesn't cover the topic. Stops agents from grounding infra/DB process answers in stale external notes when the curated copy is already in-context. (#406)
  • Current objective always injected. Lean-mode spawns now inject the live current_objective body as a dedicated "work to THIS" block (not just an index entry the agent had to remember to fetch), plus a stronger proactive-maintenance directive so agents keep current_objective, the journal, and durable memory current on their own. (#403)
  • On-demand, section-level KB access. doc_read and project_search can now pull a single heading-section of a large global knowledge page instead of the whole thing — a kb_integrations lookup drops from ~15K tokens to ~300–1.3K, and search hits carry a doc_read(slug, section=…) pointer instead of dead-ending on a teaser. (#400)
  • Cross-project distilled knowledge now applies. Fixed the experience compiler reading session outcomes through an ephemeral table, which starved it of feedstock (112 journal summaries → only 2 survived) so it produced zero global playbooks. Outcomes are now denormalized onto the durable journal row (migration 0070, with a one-shot backfill of historical rows), so the compiler sees the full corpus and its global playbooks auto-inject at spawn. (#402)

Fixed

  • Grok provider icon. Grok now shows its real brand mark in the spawn dialog and provider rail instead of the neutral letter-disc fallback. (#405)
Open on GitHub
v2.10.0 Stable

Release notes

Added Antigravity multi account. Bind a session to a specific Antigravity (agy) login, switch accounts from the session header, and manage accounts in Providers → Antigravity (discovery + guided HOME=… agy login).

Added

  • Antigravity multi-account. Bind a session to a specific Antigravity (agy) login, switch accounts from the session header, and manage accounts in Providers → Antigravity (discovery + guided HOME=… agy login). Accounts are isolated by $HOME — the agy analogue of Claude's CLAUDE_CONFIG_DIR. Switching accounts keeps the conversation: agy stores each conversation as a portable per-$HOME SQLite db, so the switch copies the current conversation into the new account's HOME and resumes it (--conversation <id>) — you continue the same chat on the other identity, only the credential/quota changes. Restarting an antigravity session resumes its conversation too. (#396)
  • Grok Build CLI provider. xAI's grok as a first-class provider (install with curl -fsSL https://x.ai/cli/install.sh | bash, then grok login; models grok-build / grok-composer-2.5-fast, bypass via --always-approve). Resolves exe/model/bypass generically — no per-CLI adapter code. (#397)
  • OpenCode local-endpoint diagnostics. When a session's local endpoint (LM Studio / Ollama / vLLM) is unreachable or serves no chat-capable model, opendray now surfaces a one-time spawn notice explaining the cause (check the URL ends in /v1, the endpoint serves on the LAN, a chat model is loaded) instead of OpenCode's opaque [buffer unavailable]. (#398)

Improved

  • Carry-context is ON by default when switching Claude accounts, and rate-limit auto-failover now carries context too — a switch seeds the new account with a recap of the prior conversation instead of starting blank. Untick the toggle for a clean-slate switch. (#395)

Removed

  • Gemini CLI provider retired, superseded by Antigravity. Removed from the install wizard, the provider catalog/UI, the opendray providers npm-update list, and the Cortex "discuss with AI" list. Existing Gemini sessions and on-disk credentials are left untouched, but the provider is no longer offered to new installs. (#397, #399)
View details

Added

  • Antigravity multi-account. Bind a session to a specific Antigravity (agy) login, switch accounts from the session header, and manage accounts in Providers → Antigravity (discovery + guided HOME=… agy login). Accounts are isolated by $HOME — the agy analogue of Claude's CLAUDE_CONFIG_DIR. Switching accounts keeps the conversation: agy stores each conversation as a portable per-$HOME SQLite db, so the switch copies the current conversation into the new account's HOME and resumes it (--conversation <id>) — you continue the same chat on the other identity, only the credential/quota changes. Restarting an antigravity session resumes its conversation too. (#396)
  • Grok Build CLI provider. xAI's grok as a first-class provider (install with curl -fsSL https://x.ai/cli/install.sh | bash, then grok login; models grok-build / grok-composer-2.5-fast, bypass via --always-approve). Resolves exe/model/bypass generically — no per-CLI adapter code. (#397)
  • OpenCode local-endpoint diagnostics. When a session's local endpoint (LM Studio / Ollama / vLLM) is unreachable or serves no chat-capable model, opendray now surfaces a one-time spawn notice explaining the cause (check the URL ends in /v1, the endpoint serves on the LAN, a chat model is loaded) instead of OpenCode's opaque [buffer unavailable]. (#398)

Changed

  • Carry-context is ON by default when switching Claude accounts, and rate-limit auto-failover now carries context too — a switch seeds the new account with a recap of the prior conversation instead of starting blank. Untick the toggle for a clean-slate switch. (#395)

Removed

  • Gemini CLI provider retired, superseded by Antigravity. Removed from the install wizard, the provider catalog/UI, the opendray providers npm-update list, and the Cortex "discuss with AI" list. Existing Gemini sessions and on-disk credentials are left untouched, but the provider is no longer offered to new installs. (#397, #399)
Open on GitHub
v2.9.1 Patch

Release notes

Fixed Escalating a Cortex discussion now jumps straight into the spawned session and continues on the same CLI + account.

Fixed

  • Escalating a Cortex discussion now jumps straight into the spawned session and continues on the same CLI + account. The escalated session surfaces immediately — web deep-links it via ?open=, mobile pushes the route — instead of only appearing on the next manual list refresh. It also inherits the conversation's provider / model / Claude-account override rather than always falling back to Claude. (#390)

Improved

  • Refreshed the third-party integration guide and its searchable kb_integrations KB page to match the shipped v2.9.0 contract: permission_mode (default | bypass) replacing the old bypass_permissions boolean, the per-principal integration:<id> memory zone, the enforced providers:write / providers:update scopes, and the reserved agent_id field. Removes the stale FORTHCOMING framing so any AI or developer reading it gets the current contract. (#391)
View details

Fixed

  • Escalating a Cortex discussion now jumps straight into the spawned session and continues on the same CLI + account. The escalated session surfaces immediately — web deep-links it via ?open=, mobile pushes the route — instead of only appearing on the next manual list refresh. It also inherits the conversation's provider / model / Claude-account override rather than always falling back to Claude. (#390)

Changed

  • Refreshed the third-party integration guide and its searchable kb_integrations KB page to match the shipped v2.9.0 contract: permission_mode (default | bypass) replacing the old bypass_permissions boolean, the per-principal integration:<id> memory zone, the enforced providers:write / providers:update scopes, and the reserved agent_id field. Removes the stale FORTHCOMING framing so any AI or developer reading it gets the current contract. (#391)
Open on GitHub
NextUpcoming

Operator polish

Operator polish, reconnect stability, memory improvements, and clearer docs.