v2.13.0
The Canvas: the agent renders a page you can actually see, mark up and
iterate on, instead of describing a screen in prose and hoping it matches.
Added
- Canvas — a visual surface for designing with the agent. The agent
renders a self-contained HTML page viacanvas_renderand it appears in
the operator's panel, where they pin a point or drag a region and send
those marks back as feedback. Marking reports the real element selector
and markup — and for a region, the components inside the frame — so the
agent iterates on the DOM instead of guessing from coordinates. Not only
UI mocks:ui,flow(flowchart),mindmap,graph(relationship
diagram) anddoc(a formatted spec page), with diagrams authored as
inline SVG so they need no external assets and stay markable node by node. - A focused canvas per project. A project accumulates many canvases, so
one is FOCUSED per cwd — scoped to the project rather than the session
because the MCP server only ever receives the cwd. Browsing the list is
free and costs nothing; only an explicit "Work on this" seeds the note
that makes ordinary conversation ("make the title bigger") resolve to that
canvas. Agents pull the same fact withcanvas_context, and a slug-less
canvas_rendertargets the focused canvas rather than creating a
duplicate. - A design system per project. Colour / type / radius / spacing tokens
plus free-text style rules, carried in every canvas request AND injected
into each rendered document as CSS variables — the pairing is what stops
successive renders from drifting apart. Ships starting palettes for people
who don't think in hex, a real colour picker, and two one-click jobs: read
the project's actual theme, or draw the system as a canvas. - Full mobile parity for all of the above: viewer, viewport switching,
focus and precise marking from the phone. opendray statusis now a systemctl-style health dashboard. On macOS
the command used to dump ~80 lines of rawlaunchctl printinternals —
a live process says nothing about whether the gateway is serving HTTP or
can reach its database. The default output is now a compact checklist:
process, HTTP health + uptime, database reachability, listen address,
restart count (with the last non-zero exit surfaced as a hint) and the
config path. The raw launchd/systemd dump moved behind--raw.
Changed
primaryin a design system means the BRAND colour, and the gateway
now says so. shadcn/ui and the Tailwind templates built on it use
--primaryfor a near-black or near-white ink and keep the brand hue in
--accent, so an agent mapping token names one-to-one produced a palette
of greys with no brand colour in it. The contract is now stated wherever
an agent reads it — the extract prompt, thecanvas_designtool schema,
the token docs and the catalog guidance — and saving a palette whose every
colour resolves to a grey returns an advisory warning saying what probably
went wrong.
Fixed
- Design-system swatches show the real colour, in any notation. Reading
a colour back fromgetComputedStyle().coloronly yieldsrgb(…)for
legacy sRGB notations — a modern colour function round-trips unchanged in
both WebKit and Chromium — so an all-oklch project got a grid of identical
grey fallbacks on the web, and mobile, which parsed nothing but#rrggbb,
got no swatches at all. The gateway now resolves hex / rgb / hsl / oklch /
oklab centrally and serves the result, which also lets the hex-only OS
colour picker edit an oklch theme without converting it one field at a
time. - Pin and region marks stay on the content they were placed on. The web
panel recorded a mark as a percentage of the visible frame and drew it in
an overlay on top of the preview, so it was anchored to the window: scroll
the canvas and the mark stayed put while the content moved out from under
it, and a mark made after scrolling was stored pointing somewhere else
entirely. Marks are now recorded in document percentages and drawn into the
canvas document itself. This also settles a mismatch where the samex/y
field meant frame percentages from the web and document percentages from
mobile. - 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/1006at
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 byproviderIdso Claude/Codex/Antigravity
(which genuinely consume the wheel) are untouched. - Coming back to the mobile app after it slept no longer fails session
loads. While the app is suspended the OS silently tears down its TCP
connections, but the HTTP client's pool didn't know — the next request
went out on a dead socket and stalled into a 30-second timeout and a
full-screen error, even on a LAN. Connection-level failures on GET/HEAD
are now replayed up to twice with backoff (a 4xx/5xx still passes
through untouched), the pool's idle timeout drops to 5 seconds so stale
sockets are rarely handed out at all, and returning from a suspension of
5+ seconds refetches the session list immediately instead of waiting for
the next tap.
Security
- Hardened the path-containment barrier behind
/fs/download,/fs/zip
and/fs/upload. The root-scoped filesystem endpoints now validate the
resolved path withfilepath.IsLocaland refuse any residual..
sequence in the canonical path (which also means oddly-named entries like
notes..mdare rejected inside these endpoints). Resolves all seven open
CodeQLgo/path-injectionalerts plus one allocation-size-overflow
finding. - Bumped vulnerable transitive npm dependencies in the web workspace
lockfile: seroval 1.6.2 (critical GHSA-mv8w-475r-vwqw), brace-expansion
5.0.9 (three DoS advisories), postcss 8.5.26 (path-traversal advisories)
and@babel/core7.29.7. Lockfile-only; no manifest changes.
Full history: CHANGELOG.md