kolu

Changelog

Newest first. On master: nix run github:juspay/kolu

Added

  • Restart kaval in one click — your session is preserved #1337

    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 #1310

    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 with kaval-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. And kaval-tui (the terminal-side client) now reaches kolu’s terminals with no --socket flag — just kaval-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) #1301

    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 list prints every live terminal (id · pid · idle · command · cwd, or --json) and kaval-tui snapshot <id> dumps a terminal’s scrollback to stdout for piping and grepping ( #1084 ), while kaval-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, --escape rebinds), 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 #1248

    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 #1298

    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 .html preview, 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 #1331

    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 #1345

    After you clicked a path:line reference 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 #1324

    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 #1303

    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 #1300

    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 #1284

    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 an n to add notes hint 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 #1280

    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 #1273

    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 #1257

    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 #1256

    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 #1249

    Clicking a link to an outside site (a different host) inside a previewed .html file 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 #1246

    Opening a terminal in a freshly git 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 #1239

    Upgrading from an older build no longer logs an EVENT_ITERATOR_VALIDATION_FAILED error 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 #1235

    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 #1247

    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 #1250

    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) #1258

    kolu’s CI runner odu now ships an MCP servernix 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`) #1262

    kolu’s CI runner odu renamed its interactive live-view command from monitor to attach — matching the “a CI runner you attach to” model — and unified it with run’s view: attaching now paints the same recipes×platforms matrix run shows, with a focused-node log pane and r to rerun the lane under the cursor. odu monitor no longer exists; use nix run .#odu -- attach.
  • Turn any @kolu/surface into an MCP server #1270

    The new sibling package @kolu/surface-mcp re-exposes any @kolu/surface spec to an MCP host — serveSurfaceAsMcp maps each cell/stream/event to a subscribable resource and each procedure (plus optional bespoke tools) to a tool under a default-deny expose allowlist, 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 (with surfaceClientRef + 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.

The first release worth a number. kolu is a terminal workspace built for scale — real xterm.js tiles on an infinite canvas, agent-agnostic, auto-detected, zero setup. Track master for the latest; pin this build with nix run github:juspay/kolu/v1.0.0.

Added

  • Infinite canvas workspace — every terminal is a draggable, resizable tile on a 2D plane. Pan, pinch-zoom, snap-to-grid, and double-click to maximize; the posture persists across reloads.
  • The dock — a two-level (rail / cards) left-edge navigator with per-repo color and agent-state pips: a violet “your turn” disk when an agent needs you, a spinning teal ring while it works, sorted by pure recency.
  • Agent-agnostic by designclaude, codex, opencode, aider, goose, gemini, and whatever ships next week all work the same way; run one once and it surfaces in the worktree-naming flow and the command palette automatically. No registry, no adapters.
  • Command palette (Cmd/Ctrl+K) — search terminals, switch themes, run actions, and drive workspace search across 20+ metadata fields.
  • Dock pings & completion toasts — when a background agent finishes, the dock pulses, a toast names the terminal with a Switch action, and a backgrounded tab gets an OS notification.
  • Git & GitHub, auto-detected — repo, branch, and CWD from OSC 7; live PR merge-state and CI checks on every navigator surface; per-repo hue coding; whole-tree git-status colors in the Code tab.
  • Rich Code tab — syntax-highlighted browsing, rendered Markdown with a source toggle, and sandboxed inline preview of agent-generated .html / .svg / .pdf / image artifacts, all live-reloading.
  • Terminals that keep up — WebGL rendering with canvas fallback, clickable path:line file references, inline images (sixel / iTerm2 / kitty), splits and tabs, and per-terminal font zoom.
  • Mobile — single-tile view with swipe navigation, a two-row soft-key bar for the keys touch keyboards lack, and a bottom-drawer inspector.

Heads-up

  • kolu ships only as a Nix flake — there are no installers. Install Nix, then nix run github:juspay/kolu. The same command updates it; add --refresh to bust the flake cache.
  • A home-manager module runs kolu as a systemd user service on Linux and a launchd agent on macOS.