Added
-
Restart kaval in one click — your session is preserved
When kaval (the daemon that owns your shells) stops mid-session, the canvas no longer just tells you to restart kolu — it gives you a Restart kaval button that recovers it in place. The same button lives in the kaval panel on the chrome bar’s identity rail, so you can also restart a running daemon to pick up a freshly deployed build. Either way kolu captures your terminals first, brings a fresh daemon up, and offers your session for restore on the empty canvas — the rail’s kaval dot shows a “restarting…” pulse throughout. (Adoption — terminals that survive a kolu update untouched — is the next step.) -
Your terminals now run in kaval, a daemon kolu spawns
kolu no longer owns your shells inside its own process — it starts kaval (the PTY daemon) and talks to it over a local socket. Day to day nothing changes: your terminals look and behave exactly as before, restored across reloads the same way. What’s new is honesty and reach. The chrome bar’s identity rail gains a kaval column with a live green/red health dot, the daemon’s build + closure-hash, and its uptime, beside the existing server and client columns — click it for a panel showing the daemon’s status and how to reach these same terminals from your shell withkaval-tui. If kaval ever stops mid-session, the canvas now says so plainly — an explicit “the terminal daemon stopped” surface with your session preserved — instead of silently looking like an empty workspace with no terminals. Andkaval-tui(the terminal-side client) now reaches kolu’s terminals with no--socketflag — justkaval-tui list/snapshot/attach. Restarting kolu still starts your terminals fresh (persistence across a daemon restart is the next step). -
kaval & kaval-tui: a standalone PTY daemon and its terminal client (beta)
kaval (Tamil kāval — watch, guard) is a small, standalone PTY daemon: it owns your shells, mirrors their screens, and serves them over a local unix socket, outliving the clients that come and go. Run it on a box where kolu has never been installed —nix run github:juspay/kolu#kaval— and drive it with kaval-tui, its terminal client:kaval-tui listprints every live terminal (id · pid · idle · command · cwd, or--json) andkaval-tui snapshot <id>dumps a terminal’s scrollback to stdout for piping and grepping ( #1084 ), whilekaval-tui attach <id>takes one over full-screen with raw passthrough — every keystroke and chord reaches the inner program, an ssh-style line-start~.detaches (~~sends a literal tilde,~?shows help,--escaperebinds), the scrollback repaints on attach, and it exits with the inner program’s code, your terminal always restored cleanly even on a crash ( #1255 ). The home-manager module installs kaval-tui alongside the server; to drive a running kolu-server’s in-process terminals instead, pass--socket $XDG_RUNTIME_DIR/kolu/pty-host.sock, and an unreachable daemon is an honest one-line error, never a hang. It’s the same code that powers kolu’s terminals, now runnable as a program of its own; kolu still embeds it in-process today, with the daemon flip to come. -
Maximize a tile without the mouse
You can now toggle a tile between the freeform canvas and maximized view straight from the keyboard with Cmd/Ctrl+Shift+M, or by running “Maximize terminal” from the command palette — no more reaching for the chrome-bar button or double-clicking a title bar. The command’s label flips to “Restore canvas” once you’re maximized, so it always names what the next click does. -
Cmd/Ctrl+F now finds in whatever you're focused on
Find-in-terminal is now confined to the terminal — the one place kolu’s search is needed, since terminal output is drawn on a canvas the browser can’t search. Press Cmd/Ctrl+F anywhere else — the Code tab’s file viewer or diff, rendered Markdown, a sandboxed.htmlpreview, the command palette, the workspace switcher — and it now hands off to your browser’s own find-in-page, which searches the real page (and reaches inside the preview frame, which terminal search never could). Click into the surface you want to search first; with focus in a terminal the chord still opens kolu’s find bar as before.
Changed
-
The Code tab's file-scope picker is now a segmented control with live change counts
The Code tab’s “All files / Local / Branch” dropdown is gone — the three views now sit side by side as a segmented control, so switching is a single click instead of open-then-pick. Because every view is visible at once, the Local and Branch segments carry a small change-count badge: you can see at a glance that you have, say, 3 uncommitted files and 12 changes versus your branch base without switching into either view. The whole-repo “All files” browser is set apart from the two git views and never badged, and each view’s description now rides a hover tooltip.
Fixed
-
Code tab remembers the file you picked, not the one you clicked in the terminal
After you clicked apath:linereference in the terminal to preview a file, then manually picked a different file in the Code tab’s tree, switching to another terminal and back used to snap the preview back to the terminal-clicked file — quietly discarding your manual pick. The clicked-file request lingered and re-fired on every terminal switch; kolu now treats it as consumed once handled, so your last selection is the one that survives the round-trip. -
The 'App updated' prompt no longer loops forever
The “App updated — Reload to apply the latest version” card could reappear immediately after every click, leaving the client stuck a build behind no matter how many times you clicked (and a manual force-reload only fixed it for a single load). The cause was in how kolu stamps its build version: the commit was baked into a JavaScript bundle the browser is told to cache for a year, so a deploy that changed only docs or other non-app files rewrote that file’s contents without changing its name — and your browser kept serving the year-cached old copy. kolu now carries the build version in the always-fresh page shell instead of the cached bundle, so a normal Reload always lands the deployed build and the card clears for good — no force-reload, no clearing site data. -
Clicking a long, wrapped URL no longer opens a clipped address
When a URL was long enough to wrap across several terminal lines, resizing the terminal — zooming a tile, resizing the window, or rearranging the canvas — could truncate it, so clicking the link opened a broken address with the middle missing. Kolu now preserves the wrapped line’s full contents through a resize, on both the live terminal and the scrollback restored when you reattach, so a wrapped link always opens the whole URL. -
Mobile key bar now types into the focused split
On a phone or tablet, the on-screen helper bar’s keys — Esc, Tab, the arrows, Ctrl-C,/, and Enter — were always sent to a tile’s main terminal, even when you’d split that tile and were working in the split. They now reach whichever terminal actually has focus, so the helper keys land in the same place your typed characters already do. -
The dock again flags Claude Code questions waiting for you
When Claude Code asks you a multiple-choice question, kolu marks that terminal as awaiting you so it surfaces in the dock — but a recent Claude Code update (v2.1.173) added ann to add noteshint to the question’s footer, which slipped between the two words kolu watched for and silently broke the detection. kolu now recognizes the new footer (and tolerates future hints landing there), so a pending question lights up the dock again instead of looking idle. -
Markdown previews now show a file's YAML front-matter
A Markdown file that opens with a---YAML front-matter block now renders that metadata as a tidy table at the top of the preview — keys beside their values, the way GitHub shows it — instead of dropping it or letting the---fences misrender as a horizontal rule and a stray heading. Front-matter that can’t be tabulated (malformed YAML, or a block that isn’t a key/value mapping) is shown raw as a code block, so it stays visible and fixable rather than silently vanishing. -
Terminal output no longer freezes until you press a key
A terminal could silently stop painting new output — an agent seemingly stuck for minutes while its work actually continued — until any keypress made everything appear at once. The cause: a viewport scroll you never made (a touch artifact, a TUI leaving its alternate screen, a scroll tick delivered late after backgrounding the tab) engaged the scroll-lock, which held all output in a buffer with nothing to ever release it. The lock now engages only for scrolls you actually make — wheel, touch, scroll keys, find-in-terminal jumps; any other scroll snaps back to the bottom and output keeps flowing. Returning to the tab also releases a lock left engaged while you were away, and the Diagnostic Info dialog now shows each terminal’s lock state and the exact transition that engaged it. -
Switching branches no longer flashes the previous branch's PR
When you switched a terminal to a different branch (or left the repo) while its PR was still being looked up, the tile could briefly show the old branch’s pull request — number, title, and CI status — until the new lookup finished, up to a few seconds later. Kolu now discards a stale in-flight lookup whose branch no longer matches, so the PR pill only ever reflects the branch you’re actually on. -
No more false GitHub auth warnings on non-GitHub repos
A terminal in a repository hosted outside GitHub (Forgejo, Codeberg, GitLab, …) used to show a “gh: not authenticated” warning on its tile and re-log it every 30 seconds — but there was nothing to authenticate; the repo simply isn’t on GitHub. Kolu now recognizes that case and stays quiet, exactly like a branch with no PR. (Real PR metadata for Forgejo and friends is planned — this stops the lie first.) -
External links in HTML previews now open in a new tab
Clicking a link to an outside site (a different host) inside a previewed.htmlfile now opens it in a new browser tab, instead of silently doing nothing or replacing the preview with the remote page. Links between files in the same preview still open in place and move the file tree, as before. -
No more error spam in fresh repos
Opening a terminal in a freshlygit init’d repository (no remote, no commits) no longer logs a repeated “no base branch found” error on every change. The Code tab’s Branch view now shows an empty diff there instead of failing — while repos that simply haven’t fetched their remote still get the actionable “run git fetch” prompt. -
No more scary error on upgrade
Upgrading from an older build no longer logs anEVENT_ITERATOR_VALIDATION_FAILEDerror at launch. Your saved Code-tab layout now carries forward cleanly instead of needing the preferences file deleted by hand. -
Terminals no longer silently freeze
A WebSocket that died without notice — a laptop sleeping, Wi-Fi roaming, or a network/proxy dropping an idle connection — used to leave a terminal frozen until you reloaded the page. A heartbeat now detects the dead connection and reconnects on its own, so live output resumes without a reload. -
Per-terminal zoom in canvas mode
Pressing Cmd/Ctrl +/- to change a terminal’s font size now zooms only the focused tile. Previously every open terminal zoomed at once, so two tiles could never be aligned to the same font size if one was zoomed before the other opened. -
Code tab keeps your tree/preview split
Resizing the split between the file tree and the preview in the Code tab now sticks. Previously, switching to another terminal (or any moment the Code tab left the screen, such as a terminal sitting outside a git repository) could silently overwrite the saved split with a garbage value, so coming back — or reloading — brought the panes up at the wrong size.
Internal
-
Drive CI from a coding agent (odu MCP server)
kolu’s CI runner odu now ships an MCP server —nix run .#odu -- mcp, wired into your agent config automatically. A coding agent (Claude Code, Codex, opencode, Gemini CLI) can start a run, snapshot the pipeline, tail a node’s log, rerun just the failed node, and block until the run settles — or the instant a node goes red — all as structured tool calls instead of scraping the terminal. The live pipeline is also a subscribable MCP resource, so notification-aware agents get pushed updates as nodes change. -
odu's live-attach command is now `odu attach` (was `odu monitor`)
kolu’s CI runner odu renamed its interactive live-view command frommonitortoattach— matching the “a CI runner you attach to” model — and unified it withrun’s view: attaching now paints the same recipes×platforms matrixrunshows, with a focused-node log pane andrto rerun the lane under the cursor.odu monitorno longer exists; usenix run .#odu -- attach. -
Turn any @kolu/surface into an MCP server
The new sibling package@kolu/surface-mcpre-exposes any@kolu/surfacespec to an MCP host —serveSurfaceAsMcpmaps each cell/stream/event to a subscribable resource and each procedure (plus optional bespoketools) to a tool under a default-denyexposeallowlist, owning the subscribe/teardown lifecycle, the zod→JSON-Schema bridge, and the stdio discipline so nobody hand-writes them twice. It builds on a new core primitive,projectSurface(withsurfaceClientRef+deriveCell/deriveStream/deriveEvent), that derives a curated surface B from a live client of surface A — a server that’s a client — so the observer-safe view an agent touches is shaped in surface-land and shared by every face.