Fixed The mouse wheel (and touch swipe) now scrolls grok and opencode sessions. These TUIs enable mouse tracking — so xterm hands them the wheel instead of scrolling its own viewport — but then ignore wheel events, scrolling only on arrow keys.
Fixed The mouse wheel (and touch swipe) now scrolls grok and opencode sessions. These TUIs enable mouse tracking — so xterm hands them the wheel instead of scrolling its own viewport — but then ignore wheel events, scrolling only on arrow keys.
Fixed
The mouse wheel (and touch swipe) now scrolls grok and opencode
sessions. These TUIs enable mouse tracking — so xterm hands them the
wheel instead of scrolling its own viewport — but then ignore wheel events,
scrolling only on arrow keys. opendray's wheel→arrow fallback was gated
behind "app hasn't grabbed the mouse", so it never ran for them and the
wheel did nothing (verified live: grok sets ?1000/1002/1003/1006 at
startup yet does nothing on button-64/65). The web terminal now recognises
these wheel-ignoring providers and sends arrow keys for both wheel and
one-finger touch scroll, scoped by providerId so Claude/Codex/Antigravity
(which genuinely consume the wheel) are untouched.
View details
Fixed
The mouse wheel (and touch swipe) now scrolls grok and opencode
sessions. These TUIs enable mouse tracking — so xterm hands them the
wheel instead of scrolling its own viewport — but then ignore wheel events,
scrolling only on arrow keys. opendray's wheel→arrow fallback was gated
behind "app hasn't grabbed the mouse", so it never ran for them and the
wheel did nothing (verified live: grok sets ?1000/1002/1003/1006 at
startup yet does nothing on button-64/65). The web terminal now recognises
these wheel-ignoring providers and sends arrow keys for both wheel and
one-finger touch scroll, scoped by providerId so Claude/Codex/Antigravity
(which genuinely consume the wheel) are untouched.
Round Table members gain live, grounded memory, the mobile session screen is rebuilt around a tool dock, and the operator takes ownership of the four global knowledge pages so their curation finally sticks.
Added
Round Table members read the shared memory. Every seated provider now
gets live, read-only access to the shared opendray-memory MCP, so
members ground their claims in the real store instead of guessing. A new
read-only mode (OPENDRAY_MEMORY_READONLY=1) exposes only the search / read
tools and refuses every write server-side — safe even with tool permissions
open — and the table prompt flips to "ground your claims via these tools".
A single per-provider attach point (catalog.AttachMemoryMCP) handles the
antigravity / codex quirks and is reusable for any spawn.
Operator owns the form of the four global KB pages. The shape of
kb_infrastructure / kb_conventions / kb_lessons / kb_reusable was
hardcoded in the drafter's prompts, so every consolidation sweep
re-manufactured the fixed fat skeleton and operator curation never stuck.
The drafter now honours each page's blueprint maintainer_mode (human →
the operator owns it outright, never drafted) and, for AI-maintained pages,
edits the operator's current structure in place — folding in only new,
on-topic evidence — instead of regenerating from a template. A per-page
prompt_hint lets the operator steer form and scope without a code change.
Set both via PUT /blueprint/{slug} (cwd __global__); a web/mobile toggle
is a follow-up. No migration — the four pages default to the previous
behaviour.
Mobile: session tool dock. The session detail screen is rebuilt so the
terminal owns the full height under a two-line AppBar title, and a new
SessionToolDock (Files · Git · Database · Vault · More) opens each tool
as a bottom sheet over the live terminal. The overflow ⋮ menu is slimmed to
session actions.
Improved
Mobile: More / settings redesigned. The flat menu is rebuilt as grouped
inset cards per section, with an account-block identity header (monogram
avatar), accent-tinted icon chips, refined typography and a version footer.
New sessions.dock.more / sessions.tools.* strings ship across en / zh /
es at 100% parity.
Fixed
A human-locked global KB page could never converge from the UI. Two bugs
are fixed: approving a divergence proposal silently dropped the lock (the
merge was written as updated_by='agent', flipping HumanLocked off) — an
approval is an operator decision, so the result now stays operator-authored
and locked; and rejecting a proposal didn't stick — the drafter re-generated
and re-filed the identical refresh every consolidation cycle. The drafter now
skips a locked page whose feedstock signature matches an already-rejected
proposal, so a rejection holds instead of nagging forever.
Docs
The README surfaces the two marquee capabilities shipped since the last pass
— Round Table (cross-vendor AI group chat + role-assigned execution
plans) and the Database tool (Postgres / MySQL / MariaDB / SQLite,
per-project crypto isolation, web + mobile) — plus staged image attachments,
TUI theme-following / wheel-scroll, and one-click provider updates.
View details
Round Table members gain live, grounded memory, the mobile session screen
is rebuilt around a tool dock, and the operator takes ownership of the four
global knowledge pages so their curation finally sticks.
Added
Round Table members read the shared memory. Every seated provider now
gets live, read-only access to the shared opendray-memory MCP, so
members ground their claims in the real store instead of guessing. A new
read-only mode (OPENDRAY_MEMORY_READONLY=1) exposes only the search / read
tools and refuses every write server-side — safe even with tool permissions
open — and the table prompt flips to "ground your claims via these tools".
A single per-provider attach point (catalog.AttachMemoryMCP) handles the
antigravity / codex quirks and is reusable for any spawn.
Operator owns the form of the four global KB pages. The shape of
kb_infrastructure / kb_conventions / kb_lessons / kb_reusable was
hardcoded in the drafter's prompts, so every consolidation sweep
re-manufactured the fixed fat skeleton and operator curation never stuck.
The drafter now honours each page's blueprint maintainer_mode (human →
the operator owns it outright, never drafted) and, for AI-maintained pages,
edits the operator's current structure in place — folding in only new,
on-topic evidence — instead of regenerating from a template. A per-page
prompt_hint lets the operator steer form and scope without a code change.
Set both via PUT /blueprint/{slug} (cwd __global__); a web/mobile toggle
is a follow-up. No migration — the four pages default to the previous
behaviour.
Mobile: session tool dock. The session detail screen is rebuilt so the
terminal owns the full height under a two-line AppBar title, and a new
SessionToolDock (Files · Git · Database · Vault · More) opens each tool
as a bottom sheet over the live terminal. The overflow ⋮ menu is slimmed to
session actions.
Changed
Mobile: More / settings redesigned. The flat menu is rebuilt as grouped
inset cards per section, with an account-block identity header (monogram
avatar), accent-tinted icon chips, refined typography and a version footer.
New sessions.dock.more / sessions.tools.* strings ship across en / zh /
es at 100% parity.
Fixed
A human-locked global KB page could never converge from the UI. Two bugs
are fixed: approving a divergence proposal silently dropped the lock (the
merge was written as updated_by='agent', flipping HumanLocked off) — an
approval is an operator decision, so the result now stays operator-authored
and locked; and rejecting a proposal didn't stick — the drafter re-generated
and re-filed the identical refresh every consolidation cycle. The drafter now
skips a locked page whose feedstock signature matches an already-rejected
proposal, so a rejection holds instead of nagging forever.
Docs
The README surfaces the two marquee capabilities shipped since the last pass
— Round Table (cross-vendor AI group chat + role-assigned execution
plans) and the Database tool (Postgres / MySQL / MariaDB / SQLite,
per-project crypto isolation, web + mobile) — plus staged image attachments,
TUI theme-following / wheel-scroll, and one-click provider updates.
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.
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.
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)
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)
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)
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)
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)
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.
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)
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)