<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>tuios releases</title>
    <link>https://tuios.dev/releases</link>
    <description>What changed in each release of tuios.</description>
    <language>en</language>
    <lastBuildDate>Fri, 02 Oct 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://tuios.dev/releases/rss.xml" rel="self" type="application/rss+xml"/>
    <image>
      <url>https://tuios.dev/brand/mark-128.png</url>
      <title>tuios releases</title>
      <link>https://tuios.dev/releases</link>
    </image>
    <item>
      <title>v0.8.5</title>
      <link>https://tuios.dev/releases/v0-8-5</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-5</guid>
      <pubDate>Fri, 02 Oct 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>tuios 0.8.5 makes tiling more configurable and lets herdr plugins run in a tuios pane. It adds a tmux-style size policy for sessions with more than one client. Scrollback keeps its text when you resize a pane.</description>
      <content:encoded><![CDATA[<p>tuios 0.8.5 makes tiling more configurable and lets herdr plugins run in a tuios pane. It adds a tmux-style size policy for sessions with more than one client. Scrollback keeps its text when you resize a pane. The sidebar files list follows the disk and panes on other machines.</p>
<p>Before you upgrade, read <a href="https://tuios.dev/releases/v0-8-5#breaking-changes-and-migration">Breaking changes and migration</a>. The pure Go emulator now reflows lines when a pane changes width.</p>
<p>The full list is at <a href="https://tuios.dev/releases">tuios.dev/releases</a>.</p>
<h2>Install</h2>
<pre><code class="language-bash">brew install tuios                     # Homebrew (macOS, Linux)
yay -S tuios-bin                       # AUR (tuios-web-bin for the web server)
nix run github:Gaurav-Gosain/tuios     # Nix
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@v0.8.5
docker run -it --rm ghcr.io/gaurav-gosain/tuios:v0.8.5
</code></pre>
<p>A binary installed by the script or from an archive updates with <code>tuios update</code>.</p>
<h2>New features</h2>
<ul>
<li><strong>Master position.</strong> The master pane can be on the left, right, top or bottom, or in the center (<a href="https://github.com/Gaurav-Gosain/tuios/pull/325">#325</a>). With <code>center</code>, the other panes go to the right and to the left in turn. This closes <a href="https://github.com/Gaurav-Gosain/tuios/issues/321">#321</a>.
<ul>
<li><code>appearance.master_position</code> sets the side. <code>appearance.master_count</code> sets how many master panes there are (1 to 9).</li>
<li>In the layout prefix (<code>Ctrl+B L</code>):
<ul>
<li><code>o</code> moves the master to the next side.</li>
<li><code>Enter</code> swaps the focused pane with the master.</li>
<li><code>m</code> focuses the master.</li>
<li><code>i</code> and <code>d</code> add and remove a master.</li>
</ul>
</li>
<li><code>tuios set-layout --master-position center --masters 2</code> changes the current workspace.</li>
<li>Each workspace keeps its own side and count, also after a daemon restart.</li>
</ul>
</li>
<li><strong>herdr plugins.</strong> In a pane, herdr's command line now answers through tuios (<a href="https://github.com/Gaurav-Gosain/tuios/pull/328">#328</a>).
<ul>
<li>terminal-browser, terminal-code and the Vim navigation plugins work in a tuios pane.</li>
<li>The herdr socket answers 8 more methods: <code>pane.process_info</code>, <code>pane.focus_direction</code>, <code>pane.neighbor</code>, <code>pane.edges</code>, <code>pane.swap</code>, <code>pane.zoom</code>, <code>workspace.focus</code> and <code>agent.start</code>.</li>
<li>Every pane gets <code>HERDR_TAB_ID</code>.</li>
<li>Each method is held to the grants of the pane that calls it. <code>pane.process_info</code> shows the command line and folder only to a pane that has <code>write</code>.</li>
</ul>
</li>
<li><strong>Session size.</strong> <code>[daemon] window_size</code> sets the size of a session that has more than one client (<a href="https://github.com/Gaurav-Gosain/tuios/pull/330">#330</a>). The values are the values of tmux's <code>window-size</code> option.
<ul>
<li><code>smallest</code> (the default) works as before.</li>
<li><code>largest</code> uses the biggest client.</li>
<li><code>latest</code> follows the client you typed in last.</li>
<li>A client smaller than the session shows the part of the session around the cursor. A mark on the line above the dock says so.</li>
<li><code>tuios set-config daemon.window_size latest -s NAME</code> changes a running session.</li>
<li>A read-only <code>tuios-web</code> viewer does not set the size under <code>largest</code> or <code>latest</code>.</li>
</ul>
</li>
<li><strong>Subagents.</strong> A Claude Code agent's rail row shows how many subagents it runs, for example <code>3 subagents</code> (<a href="https://github.com/Gaurav-Gosain/tuios/pull/307">#307</a>). Thanks to @JakeChop.</li>
</ul>
<h2>Fixes</h2>
<ul>
<li><strong>Scrollback and resize.</strong> Text no longer gets lost when a pane changes size (<a href="https://github.com/Gaurav-Gosain/tuios/pull/331">#331</a>, <a href="https://github.com/Gaurav-Gosain/tuios/pull/333">#333</a>, <a href="https://github.com/Gaurav-Gosain/tuios/pull/323">#323</a>).
<ul>
<li>A narrower pane keeps the end of each line, and a wider pane shows it again.</li>
<li>A shorter pane keeps the text below the cursor and the prompt under a full-screen program.</li>
<li>A scroll region moves its rows to history.</li>
<li>Wide characters stay in history.</li>
<li>A daemon restart keeps history rows that are wider than the pane.</li>
</ul>
</li>
<li><strong>Files list.</strong> The sidebar files list now updates when a file is added, removed or renamed (<a href="https://github.com/Gaurav-Gosain/tuios/pull/319">#319</a>, <a href="https://github.com/Gaurav-Gosain/tuios/pull/327">#327</a>). This closes <a href="https://github.com/Gaurav-Gosain/tuios/issues/313">#313</a>.
<ul>
<li>A pane on another machine updates its list when you <code>cd</code>, and when files change on that machine.</li>
<li>In a pane that runs <code>ssh</code>, the files section says that the shell is on the other machine.</li>
<li>Nothing polls. An idle session stays idle.</li>
</ul>
</li>
<li><strong>New windows in BSP.</strong> A new window now splits the focused pane, on the preselected side when you set one (<a href="https://github.com/Gaurav-Gosain/tuios/pull/349">#349</a>). Before, it always split the last pane, which is the bottom-right one. This answers discussion <a href="https://github.com/Gaurav-Gosain/tuios/discussions/347">#347</a>.
<ul>
<li>A preselection now works in daemon sessions too.</li>
<li><code>longest_side</code> reads the size of the pane it splits.</li>
</ul>
</li>
<li><strong>Zoom in the scrolling layout.</strong> Moving to the next column while zoomed no longer shows a gap during the slide (<a href="https://github.com/Gaurav-Gosain/tuios/pull/324">#324</a>).</li>
<li><strong>Log viewer.</strong> The log viewer opens on the newest entry and scrolls to the last entry it draws (<a href="https://github.com/Gaurav-Gosain/tuios/pull/329">#329</a>). Thanks to @davidreuss.</li>
<li><strong>install.sh on the BSDs.</strong> <code>install.sh</code> downloads the right archive on FreeBSD and OpenBSD (<a href="https://github.com/Gaurav-Gosain/tuios/pull/322">#322</a>). Thanks to @fdoving.</li>
<li><strong>herdr events.</strong> A client that subscribes and then acts at once now gets the event (<a href="https://github.com/Gaurav-Gosain/tuios/pull/326">#326</a>).</li>
<li><strong>Kitty images.</strong> An image in a pane started with <code>new-window -- prog</code> no longer disappears when the session state syncs (<a href="https://github.com/Gaurav-Gosain/tuios/pull/343">#343</a>).</li>
<li><strong>Speed.</strong>
<ul>
<li>The terminal emulator reads kitty and sixel image data about 15 times faster (<a href="https://github.com/Gaurav-Gosain/tuios/pull/338">#338</a>).</li>
<li>A cropped pane draws about three times faster, and a folder that changes often causes fewer sidebar redraws (<a href="https://github.com/Gaurav-Gosain/tuios/pull/335">#335</a>).</li>
</ul>
</li>
</ul>
<h2>Breaking changes and migration</h2>
<h3>Reflow</h3>
<ul>
<li>The pure Go emulator now rewraps the lines on the screen when a pane changes width, as kitty, ghostty and tmux do. Older history keeps the width it was written at.</li>
<li>On the pure Go emulator, a full-width prompt that is not marked with OSC 133 leaves one extra row each time the pane gets narrower. The ghostty emulator already did this. To stop it, mark the prompt with OSC 133. See the shell recipes in <code>tuios doctor</code>.</li>
</ul>
<h3>herdr</h3>
<ul>
<li><code>HERDR_BIN_PATH</code> in a pane now names a link to tuios that answers herdr's command line. Before, it named the tuios binary.</li>
<li>A herdr plugin that calls <code>$HERDR_BIN_PATH</code> now reaches tuios. To run the real herdr inside a tuios pane, set <code>[agents] herdr_protocol = "agents"</code> as before.</li>
</ul>
<h3>Layout keys</h3>
<ul>
<li><code>o</code>, <code>Enter</code>, <code>m</code>, <code>i</code> and <code>d</code> in the layout prefix are new defaults. If your <code>[keybindings.layout_prefix]</code> already binds one of these keys, your binding wins.</li>
</ul>
<h3>Claude Code subagents</h3>
<ul>
<li>
<p>The subagent count needs version 3 of the Claude Code integration. Run <code>tuios integration status</code>. If it reports the integration as out of date, run:</p>
<pre><code class="language-bash">tuios integration install claude-code
</code></pre>
</li>
</ul>
<h3>Mixed versions</h3>
<ul>
<li>The session size policy, the herdr command front, the files list for panes on other machines, the subagent count and master positions need a v0.8.5 daemon. To start a v0.8.5 daemon, run <code>tuios kill-server</code> after the upgrade. This closes every pane in every session, so save your work first.</li>
<li>An older client in a session under <code>latest</code> or <code>largest</code> makes the session use <code>smallest</code> until it leaves.</li>
</ul>
<h2>Contributors</h2>
<p>Thank you to everyone who sent a pull request for this release:</p>
<ul>
<li>@JakeChop: subagent count on the rail (<a href="https://github.com/Gaurav-Gosain/tuios/pull/307">#307</a>)</li>
<li>@davidreuss: log viewer scroll (<a href="https://github.com/Gaurav-Gosain/tuios/pull/329">#329</a>)</li>
<li>@fdoving: install.sh on FreeBSD and OpenBSD (<a href="https://github.com/Gaurav-Gosain/tuios/pull/322">#322</a>)</li>
</ul>
<p>Thanks to @adamcstephens for the master position request (<a href="https://github.com/Gaurav-Gosain/tuios/issues/321">#321</a>), and to @LovesAsuna for the files list reports (<a href="https://github.com/Gaurav-Gosain/tuios/issues/313">#313</a>) and the BSP report (<a href="https://github.com/Gaurav-Gosain/tuios/discussions/347">#347</a>).</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.8.3</title>
      <link>https://tuios.dev/releases/v0-8-3</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-3</guid>
      <pubDate>Thu, 01 Oct 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>tuios 0.8.3 turns the scratch terminal into a layout of its own. It adds picture-in-picture, pane history across a daemon restart, sixel images, image paste, tuios xpanes and herdr&apos;s socket API. It also brings the fixes merged since v0.8.2.</description>
      <content:encoded><![CDATA[<p>tuios 0.8.3 turns the scratch terminal into a layout of its own. It adds
picture-in-picture, pane history across a daemon restart, sixel images, image
paste, <code>tuios xpanes</code> and herdr's socket API. It also brings the fixes merged
since v0.8.2.</p>
<p>Before you upgrade, read
<a href="https://tuios.dev/releases/v0-8-3#breaking-changes-and-migration">Breaking changes and migration</a>. Every pane
now gets herdr's variables, and the scratch terminal keys changed.</p>
<p>The full list is at <a href="https://tuios.dev/releases">tuios.dev/releases</a>.</p>
<h2>Install</h2>
<pre><code class="language-bash">brew install tuios                     # Homebrew (macOS, Linux)
yay -S tuios-bin                       # AUR (tuios-web-bin for the web server)
nix run github:Gaurav-Gosain/tuios     # Nix
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@v0.8.3
docker run -it --rm ghcr.io/gaurav-gosain/tuios:v0.8.3
</code></pre>
<p>A binary installed by the script or from an archive updates with
<code>tuios update</code>.</p>
<h2>New features</h2>
<ul>
<li><strong>Scratch layouts.</strong> The scratch terminal is a small layout of its own
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/303">#303</a>). <code>Ctrl+B g</code> shows
and hides all of its panes together.
<ul>
<li>Split, move, resize and zoom its panes, as on a workspace. The window
keys act inside the box.</li>
<li>The mouse acts on the panes inside the box. A click outside the box hides
it.</li>
<li>Each <code>scratch</code> command key has its own layout. One layout is on the
screen at a time.</li>
<li><code>tuios xpanes</code> from a scratch pane opens its panes in the scratch layout.</li>
<li>After a daemon restart, each layout comes back hidden, with its panes and
their history.</li>
</ul>
</li>
<li><strong>Picture-in-picture.</strong> <code>p</code> in window mode pins the focused pane to a
corner of the screen as a small live view
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/284">#284</a>). Press <code>p</code> again
to unpin it.
<ul>
<li>The view moves to a different corner when the line you type reaches it.</li>
<li>A click on the view goes to its pane.</li>
<li><code>tuios pip [window] [--off]</code> pins a pane from a script.</li>
<li><code>[pip]</code> sets <code>width</code>, <code>height</code> and <code>corner</code>.</li>
</ul>
</li>
<li><strong>Pane history.</strong> After a daemon restart or a reboot, a restored pane shows
its old history above a dim divider
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/274">#274</a>). The new shell
starts under it.
<ul>
<li><code>[daemon] persist_scrollback</code> turns this on or off. The default is
<code>true</code>.</li>
<li><code>persist_scrollback_lines</code> (default 1000) and <code>persist_scrollback_kb</code>
(default 2048) set the limits for one pane.</li>
</ul>
</li>
<li><strong>Sixel images.</strong> A pane's sixel image shows on the host, cut to the
visible part of the pane
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/282">#282</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/pull/283">#283</a>).
<ul>
<li>Popups, borders and <code>clear</code> act on the image as they act on text.</li>
<li>A host with kitty graphics and no sixel gets a kitty image. A host with
neither shows a box.</li>
<li>A pane is told about sixel only when the host draws it. chafa, timg, lsix
and yazi then use their text fallback on other hosts.</li>
<li>This works in daemon mode, over <code>tuios ssh</code> and in <code>tuios-web</code>.</li>
</ul>
</li>
<li><strong>Image paste.</strong> <code>Ctrl+B V</code> pastes the image on your clipboard into the
focused pane as a file path
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/306">#306</a>).
<ul>
<li>tuios saves the image on the machine where the pane runs. This also works
for a pane on a host.</li>
<li>The paste key does the same when the clipboard holds only an image.</li>
<li>tuios deletes a pasted file after one hour.</li>
</ul>
</li>
<li><strong>xpanes.</strong> <code>tuios xpanes</code> opens one pane for each item on a new workspace,
with multifocus on
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/289">#289</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/pull/308">#308</a>).
<ul>
<li>Items come from the arguments or from stdin. <code>-c 'cmd {}'</code> runs a command
for each item.</li>
<li><code>-s</code> and <code>-ss</code> are speedy modes, as in tmux-xpanes. <code>--interval</code> waits
between panes.</li>
<li><code>-l</code> sets the layout: <code>tiled</code>, <code>even-horizontal</code> or <code>even-vertical</code>.</li>
</ul>
</li>
<li><strong>Close a workspace.</strong> The action <code>close_workspace</code> and
<code>tuios close-workspace [N]</code> close every pane on a workspace
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/308">#308</a>). The action asks
first.</li>
<li><strong>Copy pipes.</strong> <code>appearance.selection.copy_command</code> sends each yank in copy
mode through a command
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/288">#288</a>).
<ul>
<li>A <code>[[keybindings.copy_pipe]]</code> entry binds a copy mode key to a command.</li>
<li>The command gets the selection on stdin. Its output goes to the
clipboard.</li>
<li>When the command fails, the clipboard gets the selection.</li>
</ul>
</li>
<li><strong>Tiling scheme.</strong> <code>appearance.tiling_scheme</code> sets the BSP scheme of a new
workspace (<a href="https://github.com/Gaurav-Gosain/tuios/pull/295">#295</a>).
<ul>
<li>The values are <code>spiral</code>, <code>longest_side</code>, <code>alternate</code> and <code>smart_split</code>.
The default is <code>spiral</code>.</li>
<li><code>cycle_tiling_scheme</code> and the <code>set_tiling_scheme_*</code> actions change the
scheme of the current workspace. They have no default key.</li>
</ul>
</li>
<li><strong>herdr socket API.</strong> The tuios herdr socket answers herdr's socket API
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/301">#301</a>).
<ul>
<li>herdr's CLI, Collie's herdr adapter and other tools for herdr work in a
tuios pane.</li>
<li>Each method checks the grants of the pane that calls it.</li>
</ul>
</li>
<li><strong>herdr reports.</strong> tuios accepts all of herdr's agent protocol in every
pane (<a href="https://github.com/Gaurav-Gosain/tuios/pull/287">#287</a>).
<ul>
<li>A Crush that you start from a shell prompt reports its state.</li>
<li>tuios accepts <code>pane.report_metadata</code> and <code>notification.show</code>.</li>
<li>An agent that crashes no longer keeps its state. The pane clears when it
is back at its shell prompt.</li>
<li>When herdr's hook script and tuios's integration report for one agent,
tuios's integration wins.</li>
</ul>
</li>
<li><strong>tmux shim.</strong> The tmux shim answers the calls that Collie and other tools
make (<a href="https://github.com/Gaurav-Gosain/tuios/pull/298">#298</a>).
<ul>
<li>New commands: <code>load-buffer</code>, <code>set-buffer</code>, <code>paste-buffer</code>,
<code>delete-buffer</code>, <code>list-clients</code>, <code>show-options</code> and
<code>show-window-options</code>.</li>
<li>Control mode (<code>-C</code> and <code>-CC</code>) sends events for sessions, windows and
panes.</li>
<li>Outside every pane, the shim serves every session.</li>
</ul>
</li>
<li><strong>Verbs for adapters.</strong> These help a tool that drives tuios through the
verb socket (<a href="https://github.com/Gaurav-Gosain/tuios/pull/302">#302</a>).
<ul>
<li><code>capture-pane</code> and <code>list-windows</code> report <code>history_rows</code> and <code>revision</code>.</li>
<li>The new verb <code>list-keys</code> lists the key names that <code>send-keys</code> accepts.
The new key <code>Comma</code> sends a comma.</li>
<li><code>subscribe</code> sends a <code>workspace-renamed</code> event.</li>
<li>A session keeps its id across a daemon restart.</li>
</ul>
</li>
<li><strong>Command key recipes.</strong>
<a href="https://github.com/Gaurav-Gosain/tuios/blob/main/docs/KEYBINDINGS.md#command-keys">KEYBINDINGS.md</a>
has five recipes for command keys
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/272">#272</a>).</li>
</ul>
<h2>Fixes</h2>
<ul>
<li><strong>Focus after a close.</strong> When you close the focused pane, the focus goes to
the pane you used last on that workspace
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/286">#286</a>).</li>
<li><strong>Kitty Unicode placeholders.</strong> tuios reads <code>a=T</code> with <code>U=1</code> as a virtual
placement (<a href="https://github.com/Gaurav-Gosain/tuios/pull/300">#300</a>).
NTCharts shaders no longer flicker.</li>
<li><strong>superfile previews.</strong> superfile image previews show in the right place
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/297">#297</a>). The fix also
covers <code>kitten icat</code> with placeholders and hosts with 256 colours.</li>
<li><strong>Scratch commands.</strong> A <code>scratch</code> command key works again on the press
after a "stopped with exit code" message
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/271">#271</a>).</li>
<li><strong><code>set-agent-state</code>.</strong> From inside a pane, <code>tuios set-agent-state</code> with no
<code>--window</code> marks the pane that runs it
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/302">#302</a>).</li>
<li><strong>Screenshots.</strong> A capture file never shows as an empty file while tuios
writes it (<a href="https://github.com/Gaurav-Gosain/tuios/pull/296">#296</a>).</li>
<li><strong>Speed.</strong> Panes that print many short lines use less CPU
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/276">#276</a>). Each tuios
command starts faster
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/275">#275</a>).</li>
<li><strong>tuios-web.</strong> The <code>tuios-web</code> binary is about 260 KB smaller
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/277">#277</a>).</li>
</ul>
<h2>Breaking changes and migration</h2>
<h3>herdr</h3>
<ul>
<li>
<p>Every pane now gets <code>HERDR_ENV</code>, <code>HERDR_SOCKET_PATH</code>, <code>HERDR_PANE_ID</code>,
<code>HERDR_WORKSPACE_ID</code> and <code>HERDR_BIN_PATH</code>. <code>[agents] herdr_protocol</code> now
defaults to <code>always</code>.</p>
</li>
<li>
<p>With this default, <code>herdr</code> refuses to start inside a tuios pane. To run
herdr in a tuios pane, set this in <code>config.toml</code>:</p>
<pre><code class="language-toml">[agents]
herdr_protocol = "agents"
</code></pre>
</li>
<li>
<p><code>HERDR_PANE_ID</code> now has herdr's form, <code>w&#x3C;session>:p&#x3C;window></code>. A report with
the window id still works.</p>
</li>
</ul>
<h3>Scratch terminal</h3>
<ul>
<li>Esc no longer hides the scratch terminal. Press <code>Ctrl+B g</code> to hide it.</li>
<li>The close key closes a pane of the scratch terminal. When you close the
last pane, the scratch terminal ends.</li>
<li>The window keys act inside the scratch terminal. Before, a move, resize or
tile key hid it.</li>
</ul>
<h3>Pane history</h3>
<ul>
<li>The daemon now saves the history of each pane in the state folder. The
files hold what your panes printed, secrets included. To stop this, set
<code>persist_scrollback = false</code> in <code>[daemon]</code>. The next daemon start deletes
the saved history.</li>
</ul>
<h3>Mixed versions</h3>
<ul>
<li>Scratch layouts, pane history, image paste, <code>tuios pip</code> and the herdr
socket API need a v0.8.3 daemon. To start a v0.8.3 daemon, run
<code>tuios kill-server</code> after the upgrade. This closes every pane in every
session, so save your work first.</li>
<li>While a client of an older tuios is attached, the scratch terminal is one
pane in a popup, as in v0.8.2.</li>
</ul>
<h2>Contributors</h2>
<p>Thank you to everyone who sent a pull request for this release:</p>
<ul>
<li>@Tim4c: focus goes to the last used pane after a close
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/286">#286</a>)</li>
<li>@neomantra: kitty Unicode placeholder images
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/300">#300</a>)</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>v0.8.4</title>
      <link>https://tuios.dev/releases/v0-8-4</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-4</guid>
      <pubDate>Thu, 01 Oct 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>tuios 0.8.4 is a fix release. It repairs the default mode of tuios xpanes and removes more invisible characters from untrusted text. It also fixes the Homebrew cask warning and a race in the herdr socket.</description>
      <content:encoded><![CDATA[<p>tuios 0.8.4 is a fix release. It repairs the default mode of <code>tuios xpanes</code> and removes more invisible characters from untrusted text. It also fixes the Homebrew cask warning and a race in the herdr socket.</p>
<p>The full list is at <a href="https://tuios.dev/releases">tuios.dev/releases</a>.</p>
<h2>Install</h2>
<pre><code class="language-bash">brew install tuios                     # Homebrew (macOS, Linux)
yay -S tuios-bin                       # AUR (tuios-web-bin for the web server)
nix run github:Gaurav-Gosain/tuios     # Nix
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@v0.8.4
docker run -it --rm ghcr.io/gaurav-gosain/tuios:v0.8.4
</code></pre>
<p>A binary installed by the script or from an archive updates with <code>tuios update</code>.</p>
<h2>Fixes</h2>
<ul>
<li><strong>xpanes.</strong> In v0.8.3, <code>tuios xpanes</code> with no <code>-s</code> typed every command into the first pane, and no command ran (<a href="https://github.com/Gaurav-Gosain/tuios/pull/310">#310</a>).
<ul>
<li>Each command now goes to its own pane.</li>
<li>tuios waits for the shell prompt of the pane before it types the command.</li>
<li>With <code>-ss</code>, a pane closes when its command ends, also when no client is attached.</li>
</ul>
</li>
<li><strong>Untrusted text.</strong> The untrusted content fence removes every invisible character (<a href="https://github.com/Gaurav-Gosain/tuios/pull/314">#314</a>).
<ul>
<li>This adds the line and paragraph separators, the soft hyphen, the tag characters, the variation selectors and the other format characters.</li>
<li>A line or paragraph separator becomes a line break.</li>
<li>A zero-width joiner stays only between two emoji.</li>
<li>Mail, replies, captures from a host, notifications, agent titles and approval lines use the same rule.</li>
</ul>
</li>
<li><strong>herdr socket.</strong> A caller over the connection limit gets a <code>rate_limited</code> answer. Before, its write sometimes failed with a broken pipe (<a href="https://github.com/Gaurav-Gosain/tuios/pull/315">#315</a>).</li>
<li><strong>Pane capture.</strong> Two waits on one pane no longer race when they read its screen (<a href="https://github.com/Gaurav-Gosain/tuios/pull/315">#315</a>).</li>
<li><strong>Homebrew.</strong> The casks use <code>postflight_steps</code>. Homebrew no longer shows a deprecation warning on install or upgrade (<a href="https://github.com/Gaurav-Gosain/tuios/pull/311">#311</a>).</li>
</ul>
<h2>Upgrade</h2>
<p>The fixes to <code>-ss</code>, the fence and the herdr socket are in the daemon. To start a v0.8.4 daemon, run <code>tuios kill-server</code> after the upgrade. This closes every pane in every session, so save your work first.</p>
<h2>Thanks</h2>
<p>Thanks to @Gsirawan for reporting the invisible characters that passed the fence (<a href="https://github.com/Gaurav-Gosain/tuios/pull/312">#312</a>).</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.8.2</title>
      <link>https://tuios.dev/releases/v0-8-2</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-2</guid>
      <pubDate>Wed, 30 Sep 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>tuios 0.8.2 adds the scratch terminal and command keys. It also brings file editing and file search in the sidebar, hints on all panes and the fixes merged since v0.8.1.</description>
      <content:encoded><![CDATA[<p>tuios 0.8.2 adds the scratch terminal and command keys. It also brings file
editing and file search in the sidebar, hints on all panes and the fixes
merged since v0.8.1.</p>
<p>Before you upgrade, read
<a href="https://tuios.dev/releases/v0-8-2#breaking-changes-and-migration">Breaking changes and migration</a>. A session
rename now changes the name of the session.</p>
<p>The full list is at <a href="https://tuios.dev/releases">tuios.dev/releases</a>.</p>
<h2>Install</h2>
<pre><code class="language-bash">brew install tuios                     # Homebrew (macOS, Linux)
yay -S tuios-bin                       # AUR (tuios-web-bin for the web server)
nix run github:Gaurav-Gosain/tuios     # Nix
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@v0.8.2
docker run -it --rm ghcr.io/gaurav-gosain/tuios:v0.8.2
</code></pre>
<p>A binary installed by the script or from an archive updates with
<code>tuios update</code>.</p>
<h2>New features</h2>
<ul>
<li><strong>Scratch terminal.</strong> <code>Ctrl+B g</code> shows a scratch terminal in a popup over
the current layout. Press <code>Ctrl+B g</code> again to hide it.
<ul>
<li>Each session has one scratch terminal. The shell keeps running while the
terminal is hidden.</li>
<li>The shell starts in the folder of the focused pane. The terminal opens on
the workspace you are on.</li>
<li>The scratch terminal is shown only while it has the focus. A click
outside it or a focus on a different pane hides it.</li>
<li>Esc in window mode, the close key and the close button hide it.
<code>tuios kill-window</code> closes it.</li>
<li>The mouse does not move or resize it. Window keys do not act on a
different pane from inside it.</li>
<li>The dock, the sidebar and the tiled layout do not show it.
<code>tuios list-windows --json</code> marks it with <code>"scratch": true</code>.</li>
<li>It stays when you detach. After a daemon restart, it comes back hidden
with a new shell.</li>
<li><code>[scratch]</code> sets <code>width</code> and <code>height</code>, in cells or percent. The default
is <code>80%</code>.</li>
</ul>
</li>
<li><strong>Command keys.</strong> A <code>[[keybindings.command]]</code> entry binds a key to a
command that you write.
<ul>
<li><code>type</code> is <code>scratch</code>, <code>popup</code>, <code>pane</code> or <code>shell</code>. The default is <code>popup</code>.</li>
<li>A <code>scratch</code> entry is a popup that stays, as the scratch terminal does.
Each entry has its own popup.</li>
<li>A key that starts with <code>prefix+</code> works after the leader. Any other key
works in window mode and in terminal mode.</li>
<li>The command runs with <code>sh -c</code> in the folder of the focused pane.</li>
<li>The command gets <code>TUIOS_SESSION</code>, <code>TUIOS_SOCKET</code>, <code>TUIOS_ACTIVE_PANE_ID</code>
and <code>TUIOS_ACTIVE_PANE_CWD</code>.</li>
<li>The command palette lists each entry. <code>tuios keybinds list</code> shows them
under Commands.</li>
<li><code>tuios keybinds doctor</code> shows an entry as dead when its key is taken. A
command key never takes a key from a tuios action or the leader.</li>
<li>When a scratch command stops in its first moments, the dock shows its
exit code.</li>
</ul>
</li>
<li><strong>Hints on all panes.</strong> The new action <code>hints_all_panes</code> puts labels on all
panes that the workspace shows. It has no default key.
<ul>
<li>The focused pane gets the shortest labels.</li>
<li>tuios gives no label to text that you cannot see.</li>
<li>Set <code>hints.all_panes = true</code> to make <code>Ctrl+B F</code> put labels on all panes.</li>
</ul>
</li>
<li><strong>Sidebar file editor.</strong> <code>Shift+Enter</code> on a file in the sidebar opens it in
a new pane with an editor.
<ul>
<li>Set the editor under Settings, Sidebar, File editor. With no editor set,
tuios uses <code>$EDITOR</code>.</li>
<li>The context menu of a file has an Edit row.</li>
<li>For a session on a different machine, the dock names the editor and the
machine.</li>
</ul>
</li>
<li><strong>File search.</strong> <code>Ctrl+B f</code> searches file names below the folder of the
focused pane. <code>Ctrl+F</code> searches below the folder that the sidebar shows.
<ul>
<li>Type a name or a relative path and press <code>Enter</code>. The sidebar opens the
folder and selects the file.</li>
<li>The search skips build folders and stops after a time limit.</li>
</ul>
</li>
<li><strong>Session rename.</strong> The new command
<code>tuios rename-session [session] &#x3C;new-name></code> changes the name of a session
in the daemon.
<ul>
<li>The session picker, the sidebar and the rename key use it too.</li>
<li><code>tuios ls</code> lists the new name. The state file, mail and Inbox items move
to the new name.</li>
</ul>
</li>
<li><strong>Workspace cycling.</strong> The actions <code>next_workspace</code> and <code>prev_workspace</code>
now work. They have no default key.
<ul>
<li>They skip empty workspaces and wrap at the ends.</li>
<li>They also work in terminal mode.</li>
</ul>
</li>
<li><strong>Attach flags.</strong> <code>tuios attach --hold</code> now works for a local session.
<code>--terminal-mode</code> starts the client in terminal mode.</li>
</ul>
<h2>Fixes</h2>
<ul>
<li><strong>Kitty graphics.</strong> tuios holds the images of a pane until the pane ends
its synchronized update
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/247">#247</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/pull/249">#249</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/pull/250">#250</a>).
<ul>
<li>The Magick Arena demo and terminal-browser do not flicker.</li>
<li>A move, resize or zoom of a pane moves its image at once.</li>
<li>A hold ends after 1 second or when the pane holds too much data.</li>
</ul>
</li>
<li><strong>Status reports.</strong> A pane answers <code>CSI 5 n</code> with <code>CSI 0 n</code> and
<code>CSI ? 5 n</code> with <code>CSI ? 0 n</code>
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/257">#257</a>). ratatui-image no
longer waits forever.</li>
<li><strong>Input method text.</strong> Text from an input method reaches a pane that uses
the kitty keyboard protocol as text
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/259">#259</a>). This fixes CJK
punctuation, ideographs and emoji in Claude Code.</li>
<li><strong>OSC 66.</strong> A program that sends OSC 66 text sizing, such as opencode,
does not break the title bar of its pane
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/245">#245</a>).</li>
<li><strong>OSC 99.</strong> Builds with the ghostty backend now show OSC 99 notifications
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/242">#242</a>).</li>
<li><strong>macOS ghostty builds.</strong> The release now includes macOS archives with the
ghostty backend (<a href="https://github.com/Gaurav-Gosain/tuios/pull/244">#244</a>).</li>
<li><strong>tuios-web.</strong> sip v0.8.3 fixes a race when a web session closes
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/246">#246</a>).</li>
<li><strong><code>keybinds list-custom</code>.</strong> The command finds a rebind in every
<code>[keybindings]</code> section
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/261">#261</a>). Before, it
looked at nine sections only.</li>
<li><strong>Nested tuios.</strong>
<ul>
<li>The daemon answers a kitty frame edit in order with its other replies.
The reply no longer reaches a nested shell as keys.</li>
<li>The daemon refuses frame edits unless every attached client supports
them.</li>
</ul>
</li>
<li><strong>Popups.</strong> A popup command starts at the size of the popup.</li>
<li><strong>Hints.</strong> tuios gives no label to text that a different pane or the
screen edge hides.</li>
</ul>
<h2>Breaking changes and migration</h2>
<h3>Session rename</h3>
<ul>
<li>The session picker, the sidebar and the rename key now change the name of
the session. Before, they changed a display label only.</li>
<li>A process that runs in a pane keeps the old <code>TUIOS_SESSION</code>. tuios
commands with the old name still reach the session.</li>
<li><code>tuios attach</code> with the old name fails. The message names the new name.</li>
<li><code>tuios set-session-name</code> still sets a display label. <code>tuios ls</code> shows the
label beside the name.</li>
</ul>
<h3>Mixed versions</h3>
<ul>
<li>The scratch terminal, command keys of type <code>scratch</code> and session rename
need a v0.8.2 daemon. To start a v0.8.2 daemon, run <code>tuios kill-server</code>
after the upgrade. This closes every pane in every session, so save your
work first.</li>
</ul>
<h2>Contributors</h2>
<p>Thank you to everyone who sent a pull request for this release:</p>
<ul>
<li>@alepspizzetti: sidebar file editor and file search
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/258">#258</a>)</li>
<li>@davidreuss: workspace cycling actions
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/267">#267</a>)</li>
<li>@NotAFlightRisk: <code>keybinds list-custom</code> in every section
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/261">#261</a>)</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>v0.8.1</title>
      <link>https://tuios.dev/releases/v0-8-1</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-1</guid>
      <pubDate>Tue, 29 Sep 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>A security release. tuios ssh and tuios-web are safer to expose, and a pane and its output can do less outside the pane. It also adds hints mode, multi copy mode and the fixes merged since v0.8.0.</description>
      <content:encoded><![CDATA[<p>tuios 0.8.1 is a security release. It makes <code>tuios ssh</code> and <code>tuios-web</code> safer
to expose, and it limits what a pane and its output can do outside the pane.
It also brings hints mode, multi copy mode and the fixes merged since v0.8.0.</p>
<p>The security advisory is
<a href="https://github.com/Gaurav-Gosain/tuios/security/advisories/GHSA-jf76-3ff5-gjjv">GHSA-jf76-3ff5-gjjv</a>.
Thanks to JakeChop for reporting the issues.</p>
<p>Before you upgrade, read
<a href="https://tuios.dev/releases/v0-8-1#breaking-changes-and-migration">Breaking changes and migration</a>. Some
commands and configs that worked in v0.8.0 are refused now.</p>
<h2>Install or upgrade</h2>
<pre><code class="language-bash">brew install tuios                     # Homebrew (macOS, Linux)
yay -S tuios-bin                       # AUR (tuios-web-bin for the web server)
nix run github:Gaurav-Gosain/tuios/v0.8.1#tuios
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@v0.8.1
docker run -it --rm ghcr.io/gaurav-gosain/tuios:v0.8.1
</code></pre>
<p>A binary installed by the script or from an archive updates with
<code>tuios update</code>. Release binaries are on the
<a href="https://github.com/Gaurav-Gosain/tuios/releases/tag/v0.8.1">GitHub release</a>.</p>
<p>The release has macOS archives of the libghostty-vt build for Apple silicon
and Intel (<code>tuios-ghostty_0.8.1_Darwin_*</code>). The v0.8.0 release had none,
because the macOS build failed to link.</p>
<h2>Security fixes</h2>
<h3>Remote access</h3>
<ul>
<li><strong><code>tuios ssh</code> keys.</strong> <code>tuios ssh</code> does not accept a key that has options,
such as <code>command=</code>, <code>from=</code> or <code>restrict</code>. tuios cannot apply these options,
so it refuses the key. The log names the line of each refused key.</li>
<li><strong><code>tuios ssh</code> keys file.</strong> <code>tuios ssh</code> reads only
<code>~/.config/tuios/authorized_keys</code>. It does not read
<code>~/.ssh/authorized_keys</code> unless you name that file with <code>--authorized-keys</code>.
See <a href="https://tuios.dev/docs/cli-reference#ssh"><code>tuios ssh</code></a>.</li>
<li><strong><code>tuios-web</code> passwords.</strong> <code>tuios-web</code> can ask for a password. Use
<code>--random-password</code>, <code>--password-file</code> or the <code>TUIOS_WEB_PASSWORD</code>
environment variable. <code>--user</code> sets the user name. The default user name is
<code>tuios</code>. See <a href="https://tuios.dev/docs/web#who-can-connect">Who can connect</a>.</li>
<li><strong>Host header.</strong> On <code>localhost</code>, <code>tuios-web</code> accepts a session only when the
Host header names this machine. Use <code>--allow-host</code> to add the name of a
reverse proxy.</li>
<li><strong>Empty <code>--host</code>.</strong> An empty <code>--host</code> listens on every interface.
<code>tuios ssh</code> and <code>tuios-web</code> now apply the rules for a network address to it.</li>
<li><strong>pprof.</strong> <code>--pprof :6060</code> listens on 127.0.0.1 only. To listen on every
interface, give <code>0.0.0.0:6060</code>.</li>
<li><strong>Worktree patches.</strong> <code>tuios worktree pull</code> keeps a patch that did not apply
in a new file with a random name. Only you can read the file. The message
shows its path.</li>
</ul>
<h3>Pane grants</h3>
<ul>
<li><strong>More callers check the grants.</strong> Pane grants now cover the link sockets,
the tmux shim's pane holder, prompts, <code>send-keys</code>, <code>run-command</code> and typing
through the client protocol. See
<a href="https://tuios.dev/docs/agents#what-a-pane-may-do">What a pane may do</a>.</li>
<li><strong>Prompts.</strong> A pane without the <code>respond</code> grant cannot type into another
pane that waits on a prompt. This applies to a pane with <code>admin</code> too.</li>
<li><strong><code>send-keys</code> with <code>PREFIX</code>.</strong> <code>send-keys</code> with <code>PREFIX</code> from a pane is
refused. The message names the commands to use instead.</li>
<li><strong>Inbox answers.</strong> The Inbox refuses answers that <code>send-keys</code> typed. This
covers the digit keys, the second press of a risky allow, question answers
and the release of held mail.</li>
<li><strong>Link sockets.</strong> A process inside a pane, or a process that the daemon
started, cannot connect to a link socket.</li>
<li><strong>Wider grants wait.</strong> A <code>config.toml</code> change that widens
<code>[agents.permissions]</code>, <code>[hosts]</code> or a link policy waits for
<code>tuios config apply</code>. Run it from a terminal outside tuios. A daemon restart
also applies it. See <a href="https://tuios.dev/docs/agents#changes-that-wait">Changes that wait</a>.
<ul>
<li>A change that narrows these tables applies at once.</li>
<li>The Inbox shows an item when a change waits. <code>tuios pane-grants</code> and the
log say so too.</li>
<li>A daemon start that finds wider grants than the last run says so in the
log, in <code>tuios pane-grants</code> and in the Inbox.</li>
<li>A host that you add with "Add a host" on the settings page applies at
once.</li>
</ul>
</li>
<li><strong><code>ssh_options</code>.</strong> A host's <code>ssh_options</code> accepts only safe options, each
with one plain value, written as <code>-o Keyword=value</code>. See
<a href="https://tuios.dev/docs/configuration#rules-for-ssh_options">Rules for ssh_options</a>.
<ul>
<li>tuios drops a host with a refused option. The Inbox and <code>tuios hosts</code> name
the reason.</li>
<li><code>ProxyCommand</code>, <code>LocalCommand</code>, the known hosts files, <code>ControlPath</code> and
<code>-F</code> are refused.</li>
<li>Port forwards (<code>-L</code>, <code>-R</code>, <code>-D</code>) are refused.</li>
<li><code>-J</code> and <code>ProxyJump</code> take host names only. <code>ForwardAgent</code> takes only <code>yes</code>
or <code>no</code>.</li>
<li>A host <code>addr</code> or <code>command</code> cannot start with a dash.</li>
</ul>
</li>
</ul>
<h3>Pane output</h3>
<ul>
<li><strong>Clipboard writes.</strong> The new option <code>appearance.selection.osc52_write</code>
controls what OSC 52 from a pane does. The values are <code>off</code>, <code>ask</code>,
<code>focused</code> and <code>on</code>. The default is <code>focused</code>. See
<a href="https://tuios.dev/docs/configuration#clipboard-writes-from-a-pane">Clipboard writes from a pane</a>.
<ul>
<li>With <code>focused</code>, the focused pane sets the host clipboard. A write from
another pane shows a message in the dock. Click the message to copy the
text.</li>
<li>Each pane keeps one clipboard ask. A click copies only the text that the
dock shows.</li>
</ul>
</li>
<li><strong>Control characters.</strong> Pastes, notifications, OSC 66 text and link
addresses lose their control characters. Tabs and line breaks in a paste
stay.</li>
<li><strong>Clipboard replies.</strong> tuios drops a clipboard reply that answers no read
request of tuios.</li>
<li><strong>Kitty graphics files.</strong> A kitty graphics file must belong to you, and its
path must be absolute. tuios does not read from <code>/proc</code>, <code>/sys</code> or <code>/dev</code>,
other than <code>/dev/shm</code>. A <code>t=t</code> file name must hold <code>tty-graphics-protocol</code>.</li>
<li><strong>"cd here" and layout load.</strong> These type a <code>cd</code> only into a pane whose
shell is at its prompt. In daemon mode, the daemon does this check.
<ul>
<li>tuios types no <code>cd</code> for a folder whose name holds a quote, a backslash or
a control character. The dock says when it did not type.</li>
<li>Layout load starts each new window in its folder. It does not type a <code>cd</code>
into a new window.</li>
</ul>
</li>
</ul>
<h2>New features</h2>
<ul>
<li><strong>Hints mode.</strong> The leader and <code>F</code> label the copyable text on the focused
pane, such as URLs, paths, hashes and IP addresses. Type a label to copy its
text. See <a href="https://tuios.dev/docs/hints">Hints</a>.
<ul>
<li>Shift and a label also types the text into the pane. Ctrl and a label
opens a URL or a local path.</li>
<li>The <code>[hints]</code> table sets the patterns, the label alphabet, the open command
and the dim.</li>
</ul>
</li>
<li><strong>Multi copy mode.</strong> The copy mode key enters multi copy mode when the
focused pane is in a multifocus set of two or more panes. See
<a href="https://tuios.dev/docs/layout-modes#multi-copy-mode">Multi copy mode</a>.
<ul>
<li>Each pane gets its own cursor and selection. A search moves each pane to
its own match.</li>
<li><code>y</code> copies the selection of each pane. <code>Tab</code> cycles the format. <code>Y</code> writes
the text to a new file.</li>
<li><code>appearance.selection.multi_format</code> sets the format: <code>plain</code>, <code>markdown</code>
or <code>json</code>.</li>
</ul>
</li>
<li><strong>Multifocus.</strong>
<ul>
<li>A paste goes to every pane in the multifocus set.</li>
<li>The new actions <code>toggle_multifocus_active</code> and <code>toggle_multifocus_all</code> put
panes in the set or take them out. They have no default key.</li>
<li>With <code>appearance.dim_unfocused</code> on, panes in the set are not dimmed. Set
<code>appearance.dim_multifocus</code> to dim them again.</li>
</ul>
</li>
<li><strong>Copy mode.</strong>
<ul>
<li>Copy mode starts on the terminal cursor. Set
<code>appearance.selection.copy_entry = "center"</code> to start on the middle row.</li>
<li><code>/</code> searches forward and <code>?</code> searches back. <code>n</code> repeats the search in its
direction, and <code>N</code> goes the other way.</li>
<li>The new actions <code>copy_mode_search_forward</code> and <code>copy_mode_search_backward</code>
enter copy mode and open the search. They have no default key.</li>
</ul>
</li>
<li><strong>Focus with <code>j</code> and <code>k</code>.</strong> In window mode, <code>j</code> and <code>k</code> move focus down and
up. A config that already binds <code>j</code> or <code>k</code> there keeps its binding.</li>
<li><strong>Agent mail.</strong>
<ul>
<li>The mailbox shows each message body inside an untrusted content fence.
Each thread shows its id.</li>
<li><code>n</code> in the mailbox writes a new message to an agent in the session.</li>
<li>The new <code>[notifications.mail]</code> table controls mail alerts.</li>
</ul>
</li>
<li><strong>Other machines.</strong>
<ul>
<li>Results from another machine are marked as untrusted. <code>capture-pane</code> takes
<code>--json</code>.</li>
<li><code>send-agent-message --attach</code> to a host puts each file in the far
session's stash.</li>
</ul>
</li>
<li><strong>Agents.</strong> tuios reports the state of oh-my-pi. The detection commands
report the age of their evidence.</li>
<li><strong>Keyboard layouts.</strong> Bindings match the physical key under any keyboard
layout, non-Latin layouts too.</li>
</ul>
<h2>Fixes</h2>
<ul>
<li><strong>Nested attach.</strong> tuios refuses to attach a session from inside its own
pane, or from a pane of a session that shows it. <code>tuios attach --force</code>
skips the check. See <a href="https://tuios.dev/docs/sessions#nested-attach">Nested attach</a>.
<ul>
<li>A terminal window that you start from a pane can attach.</li>
<li>New panes do not get the variables of an outer tuios pane.</li>
</ul>
</li>
<li><strong>Layout sync.</strong> Clients send each change to the BSP tree to the daemon,
which applies and numbers it
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/230">#230</a>). Two clients that
change one layout at the same time now end on the same layout. A v0.8.0
client in the same session still works.</li>
<li><strong>Focus.</strong> The neighbour search steps to a pane that shares only one row
with the focused pane. It does not step to a diagonal pane.</li>
<li><strong>Global sessions.</strong>
<ul>
<li>The session switcher switches between sessions on other machines.</li>
<li>A machine pick goes to the daemon that can act on it.</li>
<li>One link carries more than fifteen remote panes.</li>
</ul>
</li>
<li><strong>Nix.</strong> The Nix package builds again with the correct vendor hash. CI
checks the hash on every dependency change.</li>
<li><strong>Keys.</strong>
<ul>
<li>Keypad keys, Begin and F13 and above reach the pane.</li>
<li>The leader pressed twice sends the configured leader to the pane.</li>
<li>Modifier aliases work in the leader key and in every key entry.</li>
</ul>
</li>
<li><strong>Web client.</strong> The web client gets the last output of a pane.</li>
<li><strong>Also fixed.</strong> The copy sweep runs at the frame rate. The session rail fits
narrow rows. Focus survives a stale push from another client.</li>
</ul>
<h2>Breaking changes and migration</h2>
<h3>tuios ssh</h3>
<ul>
<li><code>tuios ssh</code> does not start when there is no keys file. This applies to
<code>localhost</code> too. Before, a server on <code>localhost</code> with no keys file let every
connection in.</li>
<li>If your key is only in <code>~/.ssh/authorized_keys</code>, <code>tuios ssh</code> does not use it
now. Do one of these:
<ul>
<li>
<p>Add your public key to <code>~/.config/tuios/authorized_keys</code>:</p>
<pre><code class="language-bash">mkdir -p ~/.config/tuios
cat ~/.ssh/id_ed25519.pub >> ~/.config/tuios/authorized_keys
</code></pre>
<p>Use your public key file if it has a different name.</p>
</li>
<li>
<p>Start with <code>--authorized-keys ~/.ssh/authorized_keys</code>. tuios does not
apply the rules in <code>sshd_config</code> to these keys.</p>
</li>
<li>
<p>Start with <code>--no-auth</code>. Then every user on this machine can connect, or
everyone who reaches the port on a network address.</p>
</li>
</ul>
</li>
<li>A key with options in the keys file is not accepted. Add the key again with
no options if it must open a tuios session.</li>
</ul>
<h3>tuios-web</h3>
<ul>
<li>A bind to an address other than <code>localhost</code> needs a password. <code>--auto-tls</code>
or <code>--cert</code> alone is not enough, because TLS does not check who connects.
Add <code>--random-password</code> or <code>--password-file</code>, or add <code>--no-auth</code> on a
network you trust.</li>
<li><code>--allow-host</code> needs a password or <code>--no-auth</code>. It works only with a
loopback <code>--host</code>. Give the host name with no port.</li>
<li>On <code>localhost</code> with no password, <code>tuios-web</code> still starts. It prints one line
to say that other users on this machine can connect.</li>
<li>The password file must belong to you, with mode 600 or 400.</li>
</ul>
<h3>Pane grants</h3>
<ul>
<li>
<p><strong>Prompts.</strong> A pane that types into another pane's prompt needs the
<code>respond</code> grant. <code>admin</code> does not include it. To give it to one pane, use
<code>tuios set-pane-grants</code> or <code>--grants</code>.</p>
</li>
<li>
<p><strong><code>send-keys</code> with <code>PREFIX</code>.</strong> A script in a pane that sends <code>PREFIX</code> fails
now. Use the tuios command for the action instead, such as <code>focus-window</code>,
<code>new-window</code> or <code>split-window</code>.</p>
</li>
<li>
<p><strong><code>send-keys</code> with no window.</strong> From a pane, <code>send-keys</code> with no window types
into the focused pane. tuios does not read these keys as key bindings.</p>
</li>
<li>
<p><strong><code>run-command</code>.</strong> From a pane without <code>respond</code>, <code>run-command</code> cannot type
or press keys. Use <code>send-keys</code> or <code>send-text</code> with <code>-w</code>.</p>
</li>
<li>
<p><strong>Config changes that widen.</strong> A change that widens <code>[agents.permissions]</code>,
<code>[hosts]</code> or a link policy waits. Run this from a terminal outside tuios:</p>
<pre><code class="language-bash">tuios config apply
</code></pre>
<p><code>tuios hosts add</code> from a pane also waits for it.</p>
</li>
</ul>
<h3>ssh_options</h3>
<ul>
<li>Look in the Inbox or run <code>tuios hosts</code> after the upgrade. A host with a
refused option is dropped.</li>
<li>Move a refused option, such as <code>ProxyCommand</code> or <code>LocalForward</code>, into
<code>~/.ssh/config</code>. Then name that host in <code>addr</code>.</li>
<li>Keep port forwards (<code>-L</code>, <code>-R</code>, <code>-D</code>) in <code>~/.ssh/config</code>.</li>
<li>Write each option as <code>-o Keyword=value</code>, with one value and no quotes.</li>
</ul>
<h3>Clipboard and folders</h3>
<ul>
<li><strong>OSC 52.</strong> A program in a background pane cannot set the host clipboard
without a click. To get the v0.8.0 behaviour, set
<code>appearance.selection.osc52_write = "on"</code>.</li>
<li><strong>"cd here" and layout load.</strong> tuios types no <code>cd</code> into a pane that runs a
program. Go back to the shell prompt and try again.</li>
<li><strong>Mixed versions.</strong> A v0.8.1 client with a v0.8.0 daemon types no <code>cd</code> into
a daemon pane. To start a v0.8.1 daemon, run <code>tuios kill-server</code> after the
upgrade. This closes every pane in every session, so save your work first.</li>
</ul>
<h2>Thanks</h2>
<p>Thank you to everyone who sent a pull request for this release:</p>
<ul>
<li><strong><a href="https://github.com/masshirodev">@masshirodev</a></strong>: keypad keys, Begin and
F13 and above (<a href="https://github.com/Gaurav-Gosain/tuios/pull/195">#195</a>).</li>
<li><strong><a href="https://github.com/nathan-poncet">@nathan-poncet</a></strong>: chords read by the
key they type (<a href="https://github.com/Gaurav-Gosain/tuios/pull/209">#209</a>).</li>
<li><strong><a href="https://github.com/fonnesbeck">@fonnesbeck</a></strong>: oh-my-pi agent state
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/223">#223</a>).</li>
</ul>
<p>Thanks to JakeChop for reporting the security issues.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.8.0</title>
      <link>https://tuios.dev/releases/v0-8-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-8-0</guid>
      <pubDate>Sun, 27 Sep 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>tuios now knows what the coding agents in your panes are doing, with an Inbox for everything they wait on and a review of what they changed. Sessions live in a daemon that brings them back, panes run on other machines, a full scrollback costs a tenth of the memory, and the interface was redrawn for every colour depth and for light themes.</description>
      <content:encoded><![CDATA[<p>v0.8.0 turns tuios into a place to run coding agents. It knows what the agent
in each pane is doing, gathers everything that waits for you into one Inbox,
and shows you what an agent changed before you keep it. Your sessions live in
a daemon that brings their layout back after a restart, and a pane can run on
another machine. It is also much smaller and faster: a full scrollback costs
4.2MB per pane instead of 48MB, and startup to the first frame went from 566ms
to 68ms.</p>
<p>2,411 commits in the six months since v0.7.0. If you already run tuios, read
<a href="https://tuios.dev/releases/v0-8-0#install-or-upgrade">Install or upgrade</a> first: the daemon must be restarted,
some keys changed, and an existing config keeps running without the daemon
until you turn it on.</p>
<h2>In short</h2>
<ul>
<li><a href="https://tuios.dev/releases/v0-8-0#agents">Agents</a>: a live state for every agent pane, an
<a href="https://tuios.dev/releases/v0-8-0#the-inbox">Inbox</a> for approvals, questions, mail and finished turns,
<a href="https://tuios.dev/releases/v0-8-0#reviewing-what-an-agent-changed">a review</a> of what an agent changed, one
prompt fanned out across git worktrees, and grants that limit what a pane
may do.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#sessions-come-back">Sessions come back</a> after a daemon restart or a
reboot, and every client of a session sees one layout.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#other-machines">Other machines</a>: attach a session on another machine, or
open a single pane there, over plain <code>ssh</code>.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#the-interface">The interface</a>: a scrolling layout, a zoom camera, a rail
with files and git, a launcher, a keybind manager, the mouse everywhere, and
chrome drawn for each colour depth and for light themes.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#scripting-and-control">Scripting and control</a>: 97 JSON verbs, 167 options
you can set live, an event stream, an MCP server and a tmux shim.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#the-web-client-ssh-and-project-tapes">The web client, SSH and project tapes</a>.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#the-terminal-emulator">The terminal emulator</a>: a second backend and a
conformance suite.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#faster-and-smaller">Faster and smaller</a>, with the measured numbers, and
<a href="https://tuios.dev/releases/v0-8-0#hardening">hardening</a>.</li>
<li><a href="https://tuios.dev/releases/v0-8-0#upgrading-from-v070">Upgrading from v0.7.0</a>: every change that can break
a config, a key or a script.</li>
</ul>
<h2>Install or upgrade</h2>
<pre><code class="language-bash"># Homebrew (brew upgrade tuios to update)
brew install tuios

# The install script, which puts the release binary on your PATH
curl -fsSL https://raw.githubusercontent.com/Gaurav-Gosain/tuios/main/install.sh | bash

# Update a release binary, or one the install script put there
tuios update

# Arch Linux (AUR), Nix, Go and Docker
yay -S tuios-bin
nix run github:Gaurav-Gosain/tuios#tuios
go install github.com/Gaurav-Gosain/tuios/cmd/tuios@latest
docker run -it --rm ghcr.io/gaurav-gosain/tuios:latest
</code></pre>
<p>Release binaries for Linux, macOS, Windows and FreeBSD are on the
<a href="https://github.com/Gaurav-Gosain/tuios/releases/tag/v0.8.0">GitHub release</a>.
<code>tuios update</code> checks the download against the release checksums, and it
replaces only a binary that came from a release archive. For any other install
it names the command to run instead. Homebrew updates its formula after the
release, so <code>brew upgrade</code> can take a day to offer 0.8.0. See
<a href="https://tuios.dev/docs/getting-started">Getting started</a> for more.</p>
<p>Then, if you ran v0.7.0:</p>
<ol>
<li><strong>Restart the daemon.</strong> Run <code>tuios kill-server</code>, then <code>tuios</code>. The v0.7.0
daemon speaks an older wire protocol and is refused. This ends the programs
in its sessions, and v0.7.0 saved no layouts, so note what you want to keep
first.</li>
<li><strong>Turn on the daemon, if you want it.</strong> An existing config file keeps
running tuios standalone and floating. Add <code>daemon = true</code> and
<code>tiled = true</code> under <code>[startup]</code> to get restore and tiling
(<a href="https://tuios.dev/releases/v0-8-0#turn-on-the-daemon">details</a>).</li>
<li><strong>Install the agent integrations</strong> if you run coding agents:
<code>tuios integration install --all</code>, then <code>tuios doctor agents</code> to check.
If you installed them from a build of main, run the same command again:
<code>tuios integration status</code> says which are out of date.</li>
<li><strong>Read <a href="https://tuios.dev/releases/v0-8-0#upgrading-from-v070">Upgrading from v0.7.0</a></strong> for the keys, config
keys and script behaviour that changed.</li>
</ol>
<h2>The look</h2>
<p>The clips on this page show the default look of v0.8.0: the rail on the right,
the dock and the window titles at the top, and zoom at 95 percent so the
layout stays in view around a zoomed pane. They were recorded a few days
before the release, so a few details of the chrome are newer than the clips:
the command palette's category headers, the sectioned which-key menu, the dim
behind dialogs, and the Inbox in place of the mail dialog.
<a href="https://tuios.dev/releases/v0-8-0#defaults">Defaults</a> lists every default that changed, and how to keep the
old look.</p>
<h2>Agents</h2>
<h3>The rail shows what your agents are doing</h3>
<p>Every pane running one of 23 recognised agent CLIs (Claude Code, Codex, Gemini
CLI, opencode, Copilot, Amp, Cline, Qwen, Crush, goose, pi and more) gets a
live state: working, needs input, finished, errored or idle. The rail's agents
section lists every agent in every session in four groups: needs you, finished
and not yet seen, working, and at rest. Inside a group, rows keep the order
the panes were opened in, so a row moves only when its group changes. A
blocked agent's row shows the question it asked and how long it has waited.
Rows also show the harness, what the agent is doing, and facts it reports such
as the model, how full its context is and what it has cost.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/agents.jpg" alt="Screen recording: four agent panes in tuios, with the rail listing their states"></a></p>
<ol>
<li>Every agent in every session is in one list in the rail.</li>
<li>Finished work waits for you, marked unread.</li>
<li>A blocked agent moves to the top of the list, with its question.</li>
<li>@n in the command palette finds the pane that needs you.</li>
<li>Answer it, and the agent goes back to work.</li>
</ol>
<ul>
<li>In the command palette (<code>ctrl+p</code>), <code>@n</code> finds panes that need input and <code>@w</code>
finds working ones, across every session. <code>ctrl+b j</code> jumps to the pane
behind the last alert.</li>
<li>When a state changes, tuios can tell you with a dock message, an OSC 9
desktop notification (which reaches you over SSH) and an optional sound. The
<code>[notifications.agent]</code> table has per-state switches, a settle window so a
flapping state does not spam you, and quiet hours.</li>
<li><strong>Alerts know where you are looking.</strong> With
<code>notifications.agent.suppress_focused</code> on (the default), an alert about the
pane you are looking at is held back. tuios now asks your terminal whether
its window has focus, so when you switch to another application the alert
fires even for the focused pane. A terminal that does not report focus
counts as looking, as before.</li>
<li>The <code>after-agent-state</code> hook receives the transition in environment
variables, never in argv, so an agent's text cannot become shell arguments.</li>
<li><code>tuios set-agent-meta -w api model=opus context=41%</code> records facts the rail
draws under the row. They never change the state.</li>
<li>A person who never runs an agent sees none of this. The agent rows in the
prefix menu, the palette and the help stay hidden until an agent has been
seen.</li>
</ul>
<h3>Hooks, installed for you</h3>
<p><code>tuios integration install claude-code</code> writes tuios's hook entries into
Claude Code's settings, so the agent reports its own state instead of tuios
reading it off the screen. The hooks run <code>tuios agent-hook &#x3C;harness></code>, with no
Python. Eighteen harnesses are covered. Claude Code, Codex, Gemini CLI,
opencode, Kilo, Amp, Kimi Code CLI, Pi, Copilot, Cursor Agent and Qwen Code
report their full state; seven more report the conversation id and leave the
state to the screen rules. <code>--all</code> installs every harness whose config
directory exists, and <code>uninstall</code> and <code>status</code> undo and check them.
<code>tuios doctor agents</code> says, for every harness, whether it is on <code>PATH</code>, whether
the integration is installed and current, and which running agent panes lack
one.</p>
<ul>
<li>Crush reports its state over herdr's pane state protocol, which tuios now
speaks. <code>[agents] herdr_protocol</code> (<code>agents</code> by default, <code>always</code> or <code>off</code>)
picks which panes are told where to send it.</li>
<li>A pane that starts Codex directly gets <code>TERM_PROGRAM=WarpTerminal</code>, so Codex
sends its notifications as OSC 9 with their text instead of a bell. A shell
pane keeps <code>TUIOS</code>.</li>
<li>goose is recognised where its own installers put it. It has no hook
integration yet, and <code>tuios doctor agents</code> says so.</li>
</ul>
<h3>Detection</h3>
<ul>
<li>State comes from six ranked sources: the agent's own hook report, its
transcript, escape codes and window titles (such as Codex's "Action
Required"), screen rules that read the prompt, the foreground process, and
last of all an output stall. A lower source never overwrites a higher one
that is still fresh.</li>
<li>Agent CLIs are described by TOML manifests, bundled and overridable.
<code>tuios explain-agent-detect</code> shows why a pane was or was not recognised. The
rules have nested <code>all_of</code>, <code>any_of</code> and <code>none_of</code> groups, enough to carry
128 of herdr's 141 detection rules as written.</li>
<li>A process is identified by what it calls itself: its name, <code>argv[0]</code>, its
executable, or the script an interpreter runs. A directory called <code>claude</code> is
no longer an agent. An agent started through <code>sh -c</code>, <code>timeout</code>, <code>npx</code>,
<code>uvx</code>, <code>mise</code> or <code>nix</code> is found. This works on macOS without cgo.</li>
<li>The transcript reader reads only the last 128KB, so a 151MB transcript costs
652 microseconds.</li>
<li>Agents in panes on other machines are detected too.</li>
</ul>
<h3>The Inbox</h3>
<p><code>ctrl+b i</code> opens the Inbox: one list of everything waiting for you, in every
session and on every linked machine. Items are grouped under Approvals,
Questions, Mail, Errored and Finished, oldest first, and each one closes by
itself when what it is about stops being true. <code>ctrl+b o</code> goes to the oldest
item that needs you, and pressed again walks the rest. <code>ctrl+b O</code> does the same
for finished turns nobody has looked at.</p>
<ul>
<li>From the Inbox you can go to the pane, reply to mail with <code>r</code>, dismiss,
snooze, undo a dismiss or snooze within ten seconds, and mark a finished
turn unread.</li>
<li><strong>Peek and answer.</strong> Space on an approval or a question shows the prompt as
the pane draws it, and a digit, <code>a</code>, <code>A</code> or <code>d</code> answers it without leaving
the Inbox. A key typed by <code>send-keys</code>, <code>run-command</code> or a tape never answers.</li>
<li><strong>Approvals held for you.</strong> With <code>[agents.approvals] enabled = ["claude-code"]</code>
(or <code>opencode</code>, <code>kilo</code>, <code>qwen</code>), the hook holds a permission prompt and
puts it in the Inbox, where <code>1</code> allows once, <code>2</code> always, <code>3</code> denies and <code>n</code>
denies with a reason the model reads. It is off by default. The hold ends
after <code>hold_seconds</code> (120 by default) or when you go to the pane, and then
the harness asks in its pane as before. A failure never approves.</li>
<li><strong>Risk rules.</strong> An approval that matches a rule (recursive delete, force
push, hard reset, pipe to shell, sudo, a write outside the worktree and
others, plus your own in <code>[agents.approvals.risk]</code>) reads <code>risky:</code> and needs
a second press to allow. The rules are a speed bump, not a sandbox.</li>
<li><strong>Plans.</strong> Claude Code's plan approval is held as a plan, shown whole, and
can be approved only once its last line has been on screen.</li>
<li><strong>Questions from an agent.</strong> <code>tuios ask-human</code> puts a question with up to
nine answers in the Inbox and waits. If nobody answers in time, the answer
is mailed to the asking pane later.</li>
<li>The same data is <code>tuios list-attention</code>, and <code>tuios peek-prompt</code> and
<code>tuios respond</code> read and answer a blocked prompt from a shell.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/agent-inbox">Inbox and Review</a>.</p>
<h3>Reviewing what an agent changed</h3>
<p><code>ctrl+b v</code> on a pane, or <code>v</code> on an Inbox item or a rail agent row, opens a
full-screen review of the pane's git changes: the files beside the diff,
syntax highlighted, in a split layout when there is room. The diff is drawn for
your terminal's colour depth, so it reads the same in a truecolor terminal,
over mosh and in a 16-colour console. Leave notes on lines and send them to the
agent as one message with <code>S</code>. For a pane in a fan, <code>w</code> compares every
attempt: agent, state, lines changed and the last check. <code>tuios review</code> prints
the same diff, and <code>tuios agent-log</code> shows what an agent has been doing:
prompts, tool calls and their results, finished turns, and the commands its
shell ran.</p>
<h3>Agents can message each other, and you</h3>
<pre><code class="language-bash">tuios list-agents                      # every agent pane and its state
tuios send-agent-message -w build 'rebased onto main, please retest'
tuios read-agent-messages              # your own inbox
tuios ask-agent -w review 'which test is flaky?'   # ask and wait
</code></pre>
<p>The person at the keyboard has a mailbox called <code>human</code>. An agent writes to it
with <code>tuios send-agent-message -w human '...'</code>, the dock shows it, and
<code>ctrl+b M</code> opens the Inbox on its mail from any pane. <code>r</code> replies, and the
agent reads the answer from its own inbox. Mail sent as <code>human</code> is marked
verified only when it comes from your own client; anything else is marked as a
claim.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/mail.jpg" alt="Screen recording: an agent asks the person a question by mail, and the person answers from the mail dialog"></a></p>
<p><em>Recorded before the Inbox landed. ctrl+b M now opens the Inbox on its mail, and r still replies.</em></p>
<ol>
<li>Two agents at work. One of them needs a decision.</li>
<li>It asks you with tuios send-agent-message.</li>
<li>Ctrl+B M opens your mail, from any pane.</li>
<li>r replies. The agent gets the reply in its inbox.</li>
<li>The agent reads your answer and carries on.</li>
</ol>
<ul>
<li>A message is at most 8KB, with a subject of up to 120 characters and up to
eight attachments, sent as paths. A session's mailbox holds 256 messages or
512KB. A sender gets a burst of ten, then thirty messages a minute.</li>
<li><code>--reply-to &#x3C;id></code> answers a message and joins its thread.</li>
<li><code>ask-agent</code> refuses a question that would close a loop of agents waiting on
each other, and refuses an agent that is itself blocked on a prompt
(<code>--allow-blocked</code> overrides that).</li>
<li><code>tuios stash put &#x3C;file></code> copies a file into a store owned by the session and
prints its path, ready for <code>--attach</code>. The limits are 16MB per file and
256MB per session. <code>stash get</code> copies it back out, also across machines.</li>
<li><strong>Selectors</strong> name many agent panes at once:
<code>--select 'harness:codex state:idle,done'</code>, <code>needs:you</code>, <code>session:</code>,
<code>host:</code> and more. A write to several panes lists them and sends only when
you say yes, or with <code>--yes</code>.</li>
<li><strong>Queued messages.</strong> <code>tuios queue</code> holds a message for a busy agent and
types it once the agent has been at rest for a second.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/agent-messaging">Agent messaging</a>.</p>
<h3>One prompt, several worktrees</h3>
<pre><code class="language-bash">tuios fan 3 --agent claude 'Add a retry with backoff to the HTTP client.'
tuios fan compare
tuios fan keep api-fan-add-retry-backoff-http-2 --stash
</code></pre>
<p><code>tuios fan</code> creates several git worktrees of the repository you are in, starts
the agent in each, and types the prompt once each agent is ready to read it.
Each branch is <code>fan/</code> and the first four words of the prompt that carry
meaning, so in a repository called <code>api</code> the prompt above makes the sessions
<code>api-fan-add-retry-backoff-http</code>, <code>-2</code> and <code>-3</code>. <code>--name</code> picks the stem
yourself. The rail groups the sessions under their repository. <code>fan keep</code>
keeps one and removes the others. It refuses to throw away uncommitted work
unless you pass <code>--stash</code> (which puts it in <code>git stash</code>) or <code>--force</code>, and it
never deletes a branch.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/fan.jpg" alt="Screen recording: tuios fan starts three agents in three git worktrees, then fan keep keeps one"></a></p>
<ol>
<li>tuios fan starts one agent per git worktree.</li>
<li>Ctrl+B ) visits each session. Every agent has its own worktree.</li>
<li>tuios worktree diff shows what one of them changed.</li>
<li>fan keep keeps one. The others close, and their work goes to git stash.</li>
</ol>
<ul>
<li><code>--agent</code> takes any program with its arguments (<code>"codex --model o5"</code>), and
a comma list cycles several agents across the sessions. <code>--prompt</code> given
once per session gives each its own prompt.</li>
<li><code>tuios fan compare</code> shows each attempt's agent, state, files and lines
changed, and its last check. <code>tuios fan verify &#x3C;session> -- &#x3C;command></code> runs
one check in every attempt and records whether it passed.</li>
<li><code>tuios start-agent</code> starts one agent in a new pane and returns once it is at
its prompt. With <code>--protocol acp</code> or <code>--protocol codex</code> the agent runs
headless, over the Agent Client Protocol or the Codex app-server, and the
pane shows its turns as a transcript.</li>
<li><code>fan</code>, <code>worktree new</code> and <code>start-agent</code> also run on another machine, with
<code>--host</code>. The repository is named by its origin URL there.</li>
<li><code>tuios worktree new|ls|diff|rm</code> manages single worktrees the same way.</li>
</ul>
<p>The windows of a fan session open floating, as in the clip; <code>t</code> in window mode
tiles them (see <a href="https://tuios.dev/releases/v0-8-0#known-issues">Known issues</a>). See <a href="https://tuios.dev/docs/worktrees">Worktrees</a>.</p>
<h3>Pane grants</h3>
<p>Every pane holds grants that say what it may do through tuios: <code>read</code>,
<code>write</code> (type and leave mail in its own session), <code>fan</code>, <code>respond</code> and
<code>admin</code>. The daemon checks every call from a pane against them, and it knows a
call comes from a pane by reading the caller's process from the socket. With no
<code>[agents.permissions]</code> table a pane holds <code>admin</code>, which is what every pane
could do before. <code>mode = "strict"</code> gives a pane <code>read</code>, <code>write</code> and <code>fan</code> unless
you list others. A pane never gives more than it holds. <code>tuios pane-grants</code>
shows what the current pane may do, <code>tuios set-pane-grants</code> changes it, and
<code>start-agent</code>, <code>fan</code> and <code>new-window</code> take <code>--grants</code>.</p>
<p>Whatever the grants, a pane cannot act as the person: mail or a question sent
as <code>human</code> from inside a pane is refused, and reading your mail from a pane
only peeks.</p>
<h2>Sessions come back</h2>
<p>On a fresh install, a bare <code>tuios</code> starts or joins the daemon, which keeps
your sessions running while no client is attached. An existing config file
keeps running tuios without the daemon, and so without restore, until you turn
it on (see <a href="https://tuios.dev/releases/v0-8-0#turn-on-the-daemon">Turn on the daemon</a>). The daemon saves each
session's structure under <code>$XDG_STATE_HOME/tuios/sessions</code> and restores it
when it starts. A detach loses nothing. A daemon restart or a reboot ends the
shells: what comes back is the layout, not the programs.</p>
<ul>
<li>Each window comes back with its workspace, its place in the layout, its name
and its working directory, on Linux and on macOS. The session keeps its name
and colour.</li>
<li>Each shell is new, started in the old directory. Scrollback and running
programs are not saved. Restored shells get <code>TUIOS_RESTORED=1</code>.</li>
<li><strong>Agent conversations can come back too.</strong> When a hook recorded the
conversation id and the harness has a resume command
(<code>claude --resume &#x3C;id></code>, <code>codex resume &#x3C;id></code>, <code>opencode --session &#x3C;id></code> and
others), the restore offers it. <code>daemon.resume_agents</code> picks what happens:
<code>ask</code> (the default) puts one Inbox item per pane, answered with <code>y</code>; <code>auto</code>
types the command into the new shell; <code>off</code> does neither. A fan's worktree
records survive the restart.</li>
<li>A pane that ran on another machine comes back as a shell on this machine,
in the daemon's own directory. Restore runs before the links to other
machines are up, so it does not wait for them.</li>
<li>A state file tuios cannot read is moved aside for two weeks instead of
stopping the daemon.</li>
<li>A burst of resizes when a shell starts is written to the terminal as one, so
macOS's <code>/bin/bash</code> 3.2 is no longer killed while it starts up in a restored
pane.</li>
</ul>
<p><code>tuios daemon --no-restore</code> turns restore off. <code>tuios resurrect</code> lists what is
saved, or brings one session back by name. <code>tuios attach</code> starts the daemon
instead of refusing. See <a href="https://tuios.dev/docs/sessions">Sessions</a> and the post
<a href="https://tuios.dev/blog/sessions-come-back">Session state was saved every 30 seconds and never read back</a>.</p>
<h3>One layout for every client</h3>
<p>Two clients on one session used to disagree about pane sizes, because each
subtracted its own rail and dock and retiled. Now each client reports how much
space it reserves on each edge, the daemon takes the largest reserve per edge,
and every client gets one geometry. The same rule covers zoom, the
master-stack ratio, the scrolling layout's position, hand-arranged workspaces
and BSP trees. Session names and colours are daemon state, so a rename reaches
every client. Broadcasts reach each client in the order they were made, and a
client that attaches while another one changes the session gets the newer
state. Reattaching to a full-screen program such as <code>top</code> no longer draws its
rows one blank line apart
(<a href="https://github.com/Gaurav-Gosain/tuios/issues/123">#123</a>). The post
<a href="https://tuios.dev/blog/a-pty-has-one-size">A PTY has one size</a> explains why.</p>
<h2>Other machines</h2>
<p>The daemon keeps one <code>ssh</code> link per configured machine, run with
<code>BatchMode=yes</code>, so you need to be able to <code>ssh</code> to it without typing anything.
Nothing is nested: a remote session is drawn by your local client, with your
theme, config and prefix key.</p>
<pre><code class="language-bash">tuios hosts add build gaurav@buildbox   # or: tuios hosts add build --tailnet
tuios hosts                             # every link and its state
tuios attach --host build api           # a session on build, drawn here
tuios new-window deploy --host build    # one pane on build, in this session
tuios new deploy --global               # a session with panes from several machines
</code></pre>
<ul>
<li>The link finds tuios on the far machine by itself and redials with a backoff
when it drops. <code>tuios hosts</code> shows each link as <code>up</code>, <code>connecting</code>,
<code>reconnecting</code>, <code>unreachable</code>, <code>no_daemon</code>, <code>no_tuios</code> or <code>incompatible</code>.</li>
<li>A pane on another machine is laid out here, and its title bar says
<code>build:deploy</code>. The rail's files section and agent detection work for it.</li>
<li><strong>A dropped link no longer ends the pane.</strong> The far machine keeps it for a
grace period (<code>hosted_grace</code>, 10 minutes by default), with the last 64KB of
output, and replays that output when the link is back. Mail to a machine
whose link is down waits and is sent in order.</li>
<li><strong>Each machine decides what a linked machine may do</strong>, in <code>[hosts.NAME]</code> or
<code>[hosts."*"]</code>: <code>allow</code> lists <code>list</code>, <code>mail</code>, <code>open</code>, <code>write</code> and <code>respond</code>.
The default is every one but <code>respond</code>, so a linked machine cannot answer
prompts and approvals for you unless you allow it.</li>
<li>In a <code>global</code> session every new window asks which machine to run on.</li>
<li>Verbs take host-qualified targets: <code>-s build:api</code>, <code>-w build:api:0</code>. Every
pane gets <code>TUIOS_HOST</code>, the name of the machine it runs on.</li>
<li>The Inbox, the rail's agent counts and <code>tuios list-attention</code> cover every
linked machine.</li>
<li><code>tuios hosts tailnet</code> lists machines on your tailnet, asking the local
<code>tailscaled</code> with no root and no auth key.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/remote-hosts">Remote hosts</a> and the post
<a href="https://tuios.dev/blog/a-pane-on-another-machine">A pane on another machine</a>.</p>
<h2>The interface</h2>
<h3>Tiling, layouts and zoom</h3>
<p>A fresh install starts tiled. <code>n</code> opens a window and it takes its place in the
layout, <code>ctrl+b z</code> zooms the focused pane, and <code>alt+1</code> to <code>alt+9</code> switch
workspaces (<code>opt+1</code> to <code>opt+9</code> on macOS).</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/tiling.jpg" alt="Screen recording: new windows tile, a pane zooms, and workspaces switch"></a></p>
<ol>
<li>n opens a window, Enter types into it.</li>
<li>Each new window takes its place in the layout.</li>
<li>Ctrl+B z zooms the focused pane.</li>
<li>Alt+2 switches to an empty workspace.</li>
<li>Alt+1 brings the first one back.</li>
</ol>
<p>There are three tilers: BSP, master-stack, and a scrolling layout in the
style of niri, which puts columns on an endless horizontal strip. All three
honour <code>appearance.gap</code>.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/layouts.jpg" alt="Screen recording: switching to the scrolling layout and resizing a column to 70 percent, then moving the focus and zooming in BSP"></a></p>
<ol>
<li>Pick the scrolling layout from the command palette.</li>
<li>Panes are columns on a strip. Alt+Right slides along it.</li>
<li>Ctrl+B L 7 makes this column 70% wide.</li>
<li>Back to BSP tiling the same way.</li>
<li>Alt+N moves the focus from pane to pane.</li>
<li>Zoom slides the pane forward, and follows the focus.</li>
</ol>
<ul>
<li><strong>Zoom</strong> slides into place instead of cutting. <code>appearance.zoom_size</code> (95 by
default) zooms like a camera, with the neighbours visible at the edges, and
moving focus hands the zoom to the pane you land on
(<code>appearance.zoom_follows_focus</code>). 100 fills the screen.</li>
<li><strong>Percentage resize.</strong> <code>ctrl+b L</code> then 5 to 9 sets the focused pane's width
to 50 to 90 percent, and shift with 5 to 9 sets its height.</li>
<li><strong>Master-stack</strong> keeps your resizes across retiles, with a ratio per
workspace from 10 to 90 percent.</li>
<li><strong>Popups.</strong> <code>tuios popup -- fzf</code> runs a command in a floating pane over the
layout and closes it when the command exits. This is how fzf, gum and other
pickers become tuios overlays.</li>
<li><strong>New windows open where you are</strong>, in the focused pane's directory.</li>
<li>Resize was rebuilt so dragging a shared border moves only the two panes that
share it (<a href="https://tuios.dev/blog/one-divider-five-windows">the post</a>).</li>
</ul>
<p>See <a href="https://tuios.dev/docs/layout-modes">Layout modes</a>.</p>
<h3>The rail</h3>
<p>The rail is a sidebar of sections: sessions, terminals, files, git and agents.
It is on by default, on the right, 24 columns wide. <code>ctrl+b b</code> hides and shows
it, and <code>appearance.sidebar.enabled = false</code> keeps it off. Which sections it
draws, in what order and how tall, is one string,
<code>appearance.sidebar.sections</code>, with an editor on the settings page. The files
and git sections follow the focused pane into its directory. tuios reads the
directory from the shell's OSC 7 report when the shell sends one, and otherwise
from the process itself (see <a href="https://tuios.dev/releases/v0-8-0#known-issues">Known issues</a> for one case where
that stops).</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/rail.jpg" alt="Screen recording: the rail follows a pane into a folder, a file is created and then moved to the trash"></a></p>
<ol>
<li>The rail follows the pane into a folder.</li>
<li>Ctrl+B e moves the keyboard into the rail.</li>
<li>In the file list, a makes a file.</li>
<li>The git section counts the new file.</li>
<li>d sends it to the trash, after asking.</li>
</ol>
<ul>
<li><strong>Sessions</strong> each have a stable colour derived from the name, show their
directory and git branch, and can be renamed, dragged into an order, or
killed. Sessions on other machines are grouped under their machine.</li>
<li><strong>Files</strong> has six actions: create, rename, delete, copy, cut and paste. Only
delete asks first, and it moves the file to the freedesktop trash in
<code>$XDG_DATA_HOME/Trash</code>. Paste never overwrites.</li>
<li><strong>Git</strong> shows the branch, how far it is ahead of and behind its upstream,
and how many files changed.</li>
<li>A program can print an OSC 7 escape claiming any directory. When the kernel
says the shell is somewhere else, the file actions switch off and the rail
says "read only: wrong folder".</li>
<li><code>ctrl+b e</code> (or <code>s</code> in window mode) moves the keyboard into the rail.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/session-rail">Session rail</a>.</p>
<h3>Launcher, palette and keys</h3>
<p><code>alt+space</code> (or <code>ctrl+b a</code>) opens a launcher over everything on your <code>PATH</code>,
fuzzy-matched and ranked by how often and how recently you run things. Enter
runs the program in a new pane. Tab types it into a new pane so you can add
arguments. The command palette on <code>ctrl+p</code> finds actions, settings, and panes
in every session. With nothing typed it lists commands under category headers;
once you type, the best matches come first and the match count sits on the
search line.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/launcher.jpg" alt="Screen recording: the launcher opens a program, a popup runs fzf, and the palette finds panes"></a></p>
<ol>
<li>Alt+Space finds any program on your PATH.</li>
<li>Tab opens a pane with the program typed out, ready for arguments.</li>
<li>tuios popup floats fzf or gum over the layout.</li>
<li>The popup closes when the program exits.</li>
<li>Ctrl+P finds commands, and panes in every session.</li>
</ol>
<p>Every key tuios answers to is in one registry, and the keybind manager on
<code>ctrl+b k</code> shows it: what is bound, where tuios conflicts with itself, where it
conflicts with the program in your pane, and a Record tab that tells you who
owns the next key you press.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/keybinds.jpg" alt="Screen recording: the keybind manager searches bindings, records a key and frees it"></a></p>
<ol>
<li>Ctrl+B k lists every binding.</li>
<li>Type to search them.</li>
<li>Record: press a key, see who owns it.</li>
<li>Ctrl+D frees it, so the shell gets it back.</li>
<li>One Ctrl+B, then walk the panes with the arrows.</li>
</ol>
<ul>
<li><strong>Give a key back.</strong> <code>ctrl+d</code> on the Record tab, or
<code>tuios keybinds free &#x3C;key></code> from a shell, takes a key off every action so
the program in the pane receives it. <code>tuios keybinds doctor</code> and
<code>tuios keybinds explain &#x3C;key></code> run the same analysis from the CLI.</li>
<li><strong>Which-key.</strong> The menu after <code>ctrl+b</code> is laid out in sections (Windows,
Panes, Sessions, Modes, Menus, Tools, and Agents once an agent has been
seen) and flows into as many columns as fit. A <code>+</code> marks a key that opens
another menu. At 120 by 40 it takes 15 rows, down from 36.</li>
<li><strong>Prefix repeat.</strong> After a command worth repeating, the prefix stays armed
for a moment, so <code>ctrl+b</code> then left left left walks three panes.
<code>appearance.prefix_repeat_time</code> sets how long, and 0 turns it off.</li>
<li><strong>Lists</strong> all move the same way: the arrows, <code>ctrl+p</code> and <code>ctrl+n</code>, home,
end and the page keys, and <code>j</code>, <code>k</code>, <code>g</code> and <code>G</code> where there is no filter.
They wrap from the last row to the first (<code>appearance.wrap_lists</code>).</li>
<li><strong>New keys.</strong> <code>N</code> in window mode makes a session, <code>ctrl+b (</code> and <code>ctrl+b )</code>
switch sessions, <code>b</code> in window mode toggles the spotlight, and <code>alt+n</code> and
<code>alt+p</code> move to the next and previous window in terminal mode. Bindings
accept <code>f13</code> to <code>f63</code> and <code>insert</code>.</li>
<li><strong>Key hints</strong> in footers stay on one line: when there is no room, <code>ctrl+</code>
becomes <code>^</code>, <code>alt+</code> becomes <code>M-</code>, then labels and whole hints drop off the
end.</li>
<li><strong>macOS.</strong> <code>opt+</code> bindings on keys that compose no character, such as
<code>opt+esc</code>, now fire. When Option+Left arrives as a readline word motion,
tuios says so and names the terminal setting to change.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/keybindings">Keybindings</a>.</p>
<h3>The mouse</h3>
<ul>
<li>Right-click opens a menu for what is under the pointer: a pane, a dock
segment, a workspace pill, the desktop, a session row, or a machine heading.
Every row is an action from the keybind registry and shows its key.</li>
<li>Alt and the left button move a pane from anywhere in it. Alt and the right
button resize it. Dragging a tiled pane by its title bar swaps it on release.</li>
<li>The left button selects text and copies on release: double-click for a word,
triple-click for a line. A double click on a pane enters terminal mode
(<code>appearance.click_to_type</code>).</li>
<li>Links in a pane (OSC 8 and bare URLs, including wrapped ones) underline under
the pointer. Shift and a left click opens one. A plain click does not, so a
click on an address still focuses the pane and selects text. A <code>file://</code> link
opens in <code>$EDITOR</code> in a new pane. Under <code>tuios ssh</code> and <code>tuios-web</code> an <code>http</code>
link is copied to your clipboard instead.</li>
<li>Every overlay row highlights under the pointer and acts on a click. Dock
pills and rail sessions can be dragged into an order, and the rail's edge
can be dragged to change its width.</li>
</ul>
<h3>Look and feel</h3>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/themes.jpg" alt="Screen recording: the theme picker previews themes live, and the settings page changes an option"></a></p>
<ol>
<li>The theme picker is one palette search away.</li>
<li>Over 340 themes. The arrows preview each one live.</li>
<li>Enter keeps it.</li>
<li>Ctrl+B , opens a settings page for every option.</li>
<li>Changes show at once and are saved to config.toml.</li>
</ol>
<ul>
<li><strong>Every colour depth.</strong> The chrome is designed separately for truecolor,
256 colours and 16 colours, and tuios reads the depth from <code>TERM</code>,
<code>COLORTERM</code> and <code>NO_COLOR</code> like any other program. At 256 colours (Apple
Terminal, mosh, tmux without <code>Tc</code>) panels sit on the xterm grey ramp, so
they no longer turn navy. At 16 colours tuios paints no grounds: panels frame
themselves with a line and the selected row is reverse video. Over mosh,
which passes truecolor but not <code>COLORTERM</code>, set <code>COLORTERM=truecolor</code> on the
far side. See <a href="https://tuios.dev/docs/themes">Themes</a>.</li>
<li><strong>Light themes.</strong> Dialogs, the palette, which-key, settings, the Inbox and
help are drawn on a ramp built from a light theme's background, where they
used to be a dark slab, and text is darkened at its own hue until it reads.</li>
<li><strong>Your terminal's colours.</strong> With no theme and no pane background set, each
client asks its own terminal for its background, foreground and 16 colours,
and a program in a pane that asks for them (OSC 10, 11 and 4) gets those
answers. A local client follows your system's light and dark switch as it
happens.</li>
<li><strong>Themes.</strong> 343 built-in themes with a live preview. <code>tuios import-theme</code>
converts a kitty, ghostty, alacritty or wezterm scheme. A theme can carry
<code>chrome</code> colours for the interface, so the accent can be amber without
turning every blue in your panes amber.</li>
<li><strong>Backgrounds.</strong> A cell a program leaves on the default background shows
your terminal through it. <code>appearance.pane_background</code> can now paint it:
<code>off</code> (the default), <code>theme</code>, or a <code>#RRGGBB</code> colour. The desktop, window
chrome, dock and rail have the same option, and <code>appearance.background</code>
sets them all.</li>
<li><strong>Motion.</strong> <code>appearance.motion</code> is <code>full</code> (the default), <code>basic</code> (window
slides and zoom only) or <code>none</code>. It replaces <code>animations_enabled</code>. With
<code>full</code>, dialogs fade in (in truecolor) and a working agent's row carries a
slow shimmer.
<code>appearance.modal_dim</code> (30 by default, 0 for off) dims what is behind a
dialog.</li>
<li><strong>Settings page</strong> on <code>ctrl+b ,</code> (or <code>,</code> in window mode) covers every option,
with a colour picker, sliders for numbers, an editor for the rail sections
and pickers with previews. <code>/</code> searches every row by name, config key, value
and description. A row that differs from the default has a dot, backspace
resets it, and <code>ctrl+z</code> undoes. Changes apply at once and are saved to
<code>config.toml</code>. Editing the file by hand also reaches the running client, and
an error is shown on screen instead of being ignored.</li>
<li><strong>Glyph sets.</strong> <code>appearance.glyphs</code> picks the shapes of borders, window
controls and rail marks: <code>default</code>, <code>unicode</code>, <code>heavy</code>, <code>ascii</code>, or your own
file. With none set, a locale that is not UTF-8 gets ASCII, and the Linux
console gets plain Unicode. <code>tuios list-glyphs</code> says what was picked and why.</li>
<li><strong>Zen mode</strong> hides unfocused borders, always or while the mouse is still.</li>
<li><strong>Copy flash</strong> sweeps a band of light over copied text.</li>
<li><strong>Keycast</strong> draws your keypresses in a corner for screen recordings
(<code>tuios --show-keys</code>, or from the palette).</li>
</ul>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/spotlight.jpg" alt="Screen recording: a shake of the mouse turns on the spotlight, the beam follows the pointer across panes and the rail, and another shake turns it off"></a></p>
<ol>
<li>With spotlight.shake on, a shake of the mouse turns the spotlight on.</li>
<li>The beam follows the pointer, and the rest of the screen dims.</li>
<li>It lights whatever is under the pointer, panes and the rail alike.</li>
<li>Shake again, or press b in window mode, to turn it off.</li>
</ol>
<ul>
<li><strong>Spotlight.</strong> <code>b</code> in window mode, or a shake of the mouse with
<code>spotlight.shake</code> on, dims everything outside a circle around the mouse or
the cursor. The <code>[spotlight]</code> table sets the radius, how dark the rest goes,
a hard or soft edge, and what it follows.</li>
</ul>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/screensaver.jpg" alt="Screen recording: S starts the screen saver, the view pulls back to a grid of all 36 effects, each recorded on the same screen, and a key brings the screen back"></a></p>
<ol>
<li>In window mode, S starts the screen saver.</li>
<li>It is made from what is on your screen.</li>
<li>All 36 effects, each recorded on the same screen and shown until it puts the screen back together.</li>
<li>Any key brings the screen back.</li>
</ol>
<ul>
<li><strong>Screen saver.</strong> 36 effects ported from terminaltexteffects, drawn from your
real screen. Off until you set <code>screensaver.enabled</code>. <code>S</code> in window mode
starts it now, and any key brings the screen back.</li>
</ul>
<h3>Screenshots and graphics</h3>
<p><code>ctrl+b C</code> captures a pane, the whole screen, or a region you drag with the
mouse, and shows a preview with the file it wrote. It works while a panel is
open too, so the Inbox, the review, the palette or a dialog can be in the
picture. On a terminal with kitty graphics the preview shows the picture
itself. <code>tuios screenshot</code> does the same from a script. It runs in the daemon
from the emulator's cell grid, so it works on a detached session, and writes
<code>png</code>, <code>svg</code>, <code>html</code>, <code>ansi</code> or <code>txt</code> in any theme.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/screenshot.jpg" alt="Screen recording: chafa draws an image in a pane with kitty graphics and the image moves with its pane, capture mode takes a screenshot of a pane, then tuios screenshot writes a PNG that chafa shows"></a></p>
<ol>
<li>Programs that speak the kitty graphics protocol, such as chafa, draw images in any pane.</li>
<li>Move the pane and the picture goes with it.</li>
<li>Ctrl+B C captures a pane, the whole screen or a dragged region.</li>
<li>The preview is the PNG it wrote, drawn with kitty graphics.</li>
<li>tuios screenshot does the same from a script: PNG, SVG, HTML, ANSI or plain text, in any theme.</li>
</ol>
<ul>
<li><strong>Kitty graphics animation</strong> is implemented, sending only the changed
regions. One measured page went from 330MB forwarded in 21.6 seconds at
17fps to 22MB at 73fps.</li>
<li><strong>Unicode placeholders</strong>, such as the images in glow's pager, show inside a
pane and scroll with the text.</li>
<li>A window over part of an image crops that part instead of hiding the whole
image. Images no longer draw over the rail or the dock, and two panes that
both number an image 1 no longer replace each other's picture.</li>
<li><code>kitten icat</code> and payloads with line breaks draw now.</li>
<li><strong>Graphics over SSH</strong> follow the connecting client's capabilities.</li>
<li><strong>Bounded memory.</strong> An animated gif under chafa grew tuios to 5.3GB in two
minutes. The same run now stays at 189MB.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/screenshots">Screenshots</a>.</p>
<h2>Scripting and control</h2>
<p>The daemon speaks 97 verbs over a line-delimited JSON socket. <code>tuios list-verbs</code> lists them with their parameters and every error code they can
return. One registry holds 167 options, and each one can be set in a running
session.</p>
<p><a href="https://tuios.dev/releases/v0-8-0"><img src="https://tuios.dev/releases/v0.8.0/control.jpg" alt="Screen recording: set-config changes options live, subscribe prints events, and wait-for blocks until a pane prints a line"></a></p>
<p><em>Recorded when tuios had 156 options. v0.8.0 has 167.</em></p>
<ol>
<li>set-config changes any option in the running session.</li>
<li>subscribe prints each event as a JSON line.</li>
<li>wait-for blocks until a pane prints what you are waiting for.</li>
<li>Themes too. Every option changes live.</li>
</ol>
<ul>
<li><strong>Strict input.</strong> A parameter a verb does not take is refused with the
closest spelling, instead of being dropped. <code>set-option</code> refuses a path that
does not exist, a bad colour or an unknown theme. <code>run-command</code> refuses a
name it does not know (<code>tuios run-command --list</code>).</li>
<li><strong><code>tuios run -w NAME -- cmd</code></strong> types one command into a pane, waits for it,
prints exactly its output and exits with its status, for a shell that marks
its commands with OSC 133. <code>wait-for command-finished</code> waits for one, and
<code>capture-pane --last-command</code> reads what the last one printed.</li>
<li><strong><code>tuios subscribe</code></strong> prints the daemon's events as JSON lines, and resumes
after a disconnect with <code>--after-seq</code> and <code>--boot-id</code>.</li>
<li><strong><code>tuios wait-for</code></strong> blocks until a pane prints a pattern, exits, goes idle,
or an agent reaches a state, in one session or with <code>--any-session</code>.</li>
<li><strong>MCP server.</strong> <code>tuios mcp</code> serves the control surface as Model Context
Protocol tools over stdio. The default tools read, wait and send mail;
<code>--write</code> adds typing into panes, answering prompts and fan-out. Each call
is held to the pane it came from.</li>
<li><strong>tmux shim.</strong> <code>tuios tmux-shim &#x3C;command></code> runs a tool that only knows how to
open tmux panes, such as Claude Code's agent teams, with a <code>tmux</code> that
answers in your tuios session. It is opt in.</li>
<li><strong><code>send-keys -w NAME</code></strong> sends the keys to that window even with a client
attached, and says where they went. <code>-w</code> tries a window's id, its index,
then its exact name, and only then an id prefix, so a window named <code>db</code>
cannot be mistaken for another window whose id starts with <code>db</code>.</li>
<li><strong>Hooks run in the daemon</strong>, so they fire with nobody attached. <code>tuios list-hooks</code> shows each hook's runs, last exit code and last error. A new
hook, <code>after-command-finished</code>, fires when a marked command finishes.</li>
<li><strong><code>new-session</code>, <code>split-window</code>, <code>set-layout</code></strong> and the other verbs work
with no client attached. <code>tuios layout export &#x3C;name></code> prints a tape script
that <code>tuios tape play</code> runs.</li>
<li><strong>Errors say what to do.</strong> Every CLI failure prints the cause and a fix.</li>
<li><strong>One daemon per runtime directory.</strong> The socket lives under
<code>XDG_RUNTIME_DIR</code>, or <code>/tmp/tuios-&#x3C;uid></code> without it, and the daemon refuses
that directory if it is a symlink or another user owns it. <code>TUIOS_SOCKET</code> in
a pane names the daemon the pane belongs to, and a command refuses one that
names no running daemon. To run a separate daemon, set <code>XDG_RUNTIME_DIR</code> and
<code>XDG_STATE_HOME</code>.</li>
<li><strong><code>tuios update</code></strong> replaces the binary, but only when it installed it. It
verifies checksums and otherwise names the package manager that owns it.</li>
<li><strong><code>tuios --skill</code></strong> prints a short core for an agent driving tuios from a
pane, and <code>tuios --skill TOPIC</code> one of thirteen topics. A test checks every
command in it against the real command tree.</li>
<li>The daemon writes a log to <code>$XDG_STATE_HOME/tuios/daemon.log</code>, and a panic in
the interface shows a crash report you can copy or file, with no pane
contents in it.</li>
</ul>
<p>See <a href="https://tuios.dev/docs/control-protocol">the control protocol</a> and the post
<a href="https://tuios.dev/blog/the-daemon-said-yes-to-an-option-that-did-not-exist">The daemon said yes to an option that did not exist</a>.</p>
<h2>The web client, SSH and project tapes</h2>
<ul>
<li><strong><code>tuios ssh</code> checks keys.</strong> See <a href="https://tuios.dev/releases/v0-8-0#ssh">SSH</a> under Upgrading.</li>
<li><strong><code>tuios-web</code> over TLS.</strong> <code>--auto-tls</code> creates and keeps a certificate for
the hostname and every interface address, so you can open a LAN address on
your phone. On a phone, a row of tuios commands sits near your thumb, a long
press opens the pane menu, and dividers are wide enough to grab.</li>
<li>The web client shows your theme, takes every interface flag <code>tuios</code> takes,
and can shape Arabic and ligatures with HarfBuzz (opt in). The Docker image
includes <code>tuios-web</code>.</li>
<li><strong>tuios in a browser tab.</strong> tuios also builds for WebAssembly, with a
pretend shell in every pane and no server. That build runs the guided tour
at <a href="https://tuios.dev/learn">/learn</a>.</li>
<li><strong>Project tapes.</strong> A <code>.tuios.tape</code> in a project describes its session:
windows, commands and layout. When a shell <code>cd</code>s into the project, tuios
offers to run it, like direnv for layouts. You read the file first, and
trust is tied to its hash, so any edit asks again. See
<a href="https://tuios.dev/docs/project-tapes">Project tapes</a>.</li>
<li><strong>Install.</strong> Homebrew core has <code>tuios</code>. The Nix package is repaired and
ships <code>tuios-web</code>. <code>scripts/install.sh</code> installs to <code>~/.local/bin</code>.</li>
</ul>
<h2>The terminal emulator</h2>
<p>Behind a <code>ghostty</code> build tag, panes can run on libghostty-vt, Ghostty's
emulation core, instead of the pure Go emulator. Package managers install the
pure Go build, and so does <code>scripts/install.sh</code> unless you pass <code>ghostty</code>.
The GitHub release adds <code>tuios-ghostty</code> archives built with libghostty-vt for
Linux and Windows; macOS archives will follow in a later release.
<code>tuios --version</code> names the backend. A differential suite feeds both the same
bytes and compares the results.</p>
<p>A conformance corpus, a grammar-based fuzzer, differential tests against tmux
and two metamorphic checks found bugs that any program in a pane could hit:</p>
<ul>
<li>The cursor position report had line and column swapped.</li>
<li>Under <code>TERM=screen</code>, box drawing came out as <code>lqk</code>.</li>
<li>OSC 8 hyperlinks had their fields swapped and never worked.</li>
<li>A scroll region taller than the screen crashed the daemon and every session
in it.</li>
<li>A window title with a Dingbats character, which Claude Code puts in its
title, ended early and printed the rest into the pane.</li>
<li>NEL, DECALN, DECSTR, DECRQSS, REP, DECSED, DECSEL, HPB, VPB, mode 47 and
more were missing or wrong.</li>
<li>Home and End reach a shell that turned on application cursor keys, as zsh
does, in the form it binds
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/193">#193</a>).</li>
<li>A session made by a command with no terminal, such as <code>tuios new --detach</code>
from a script or CI, gave every pane <code>TERM=dumb</code> for its life. Those panes
now get <code>xterm-256color</code>.</li>
</ul>
<h2>Faster and smaller</h2>
<p>Every number comes from the commit that made the change or from <code>docs/perf.md</code>
in the tuios repository. Each row is a before and after pair measured around
one change during this cycle, on the machine and setup that change was
measured on. It is not a run of v0.7.0 against v0.8.0.</p>
<table>
<thead>
<tr>
<th>What</th>
<th>Before</th>
<th>After</th>
</tr>
</thead>
<tbody>
<tr>
<td>Scrollback, 10,000 lines per pane</td>
<td>48MB</td>
<td>4.2MB</td>
</tr>
<tr>
<td>Empty 207x55 pane</td>
<td>1.7MB</td>
<td>28KB</td>
</tr>
<tr>
<td>Startup to first frame</td>
<td>566ms</td>
<td>68ms</td>
</tr>
<tr>
<td>Keypress to echo, median</td>
<td>9.75ms</td>
<td>1.78ms</td>
</tr>
<tr>
<td>Typing while another pane floods, median</td>
<td>18 to 28ms</td>
<td>0.9 to 5.4ms</td>
</tr>
<tr>
<td>Typing one letter</td>
<td>18.9us, 177 allocations</td>
<td>1.06us, 14</td>
</tr>
<tr>
<td>Workspace switch, per pane</td>
<td>47.6ms</td>
<td>2.4ms</td>
</tr>
<tr>
<td>Kitty animation, one page</td>
<td>330MB at 17fps</td>
<td>22MB at 73fps</td>
</tr>
<tr>
<td>Animated gif under chafa</td>
<td>5.3GB</td>
<td>189MB</td>
</tr>
<tr>
<td>Stripped binary, darwin/arm64</td>
<td>29,971,890 bytes</td>
<td>23,797,538 bytes</td>
</tr>
</tbody>
</table>
<p>An idle client schedules no timer renders: with idle shells and the rail open,
a 10 second test sees no bytes on the wire and no renders. The motion setting
keeps it that way: the clock that drives a fade or a shimmer is never armed
when nothing moves. The binary lost 6MB across seven changes, and CI now fails
a change that grows the release binary past a budget. The posts
<a href="https://tuios.dev/blog/48mb-per-pane-twice">48MB per pane, twice</a>,
<a href="https://tuios.dev/blog/a-fifth-of-every-frame-went-to-changing-nothing">A fifth of every frame went to changing nothing</a>
and <a href="https://tuios.dev/blog/making-the-binary-smaller">Making the binary smaller</a> cover three of
these.</p>
<h2>Hardening</h2>
<ul>
<li><strong>Messages the daemon decodes are bounded.</strong> A state update or command
result nested deeply enough could run the daemon out of stack while it was
decoded, which stopped every session. Frames, trees and nested payloads now
have limits, checked before decoding.</li>
<li><strong>Debug logs</strong> (<code>TUIOS_DEBUG_INTERNAL=1</code>), one of which records keys typed
in terminal mode, are opened privately, and a log file another user planted
is refused. They used to be readable by others and to follow symlinks.</li>
<li>A host whose address starts with <code>-</code> is ignored, so <code>ssh</code> cannot read it as
an option.</li>
<li>A client can no longer overwrite what the daemon owns about a window, such
as its agent state or directory.</li>
<li>The test suite was held to one rule: a unit test stays only when it catches
a real bug the end-to-end suite misses. The end-to-end tests, which drive a
real tuios binary against real daemons, went from 347 to 423, and the fuzz
targets from 22 to 32.</li>
</ul>
<h2>Other fixes</h2>
<ul>
<li>The last output of a pane, often its prompt, sometimes stayed invisible
until the next key. It is drawn at once.</li>
<li>A pane scrolled back stays on the line you stopped at while output arrives.</li>
<li>Clipboard copy and paste work on GNOME Terminal and other VTE terminals, and
over a loopback SSH connection, using the native clipboard tool.</li>
<li>Keys typed within 150ms of entering terminal mode are no longer dropped.</li>
<li><code>ctrl+d</code> in a pane on another machine closes it at once.</li>
<li>Two connections accepted in the same microsecond on macOS got one client id,
and the second replaced the first.</li>
<li>The keybind manager reads the foreground program of a pane on macOS.</li>
<li>Under tmux 3.6 and later, a few cells beside a panel showed the terminal's
own background, because the renderer moved the cursor with hard tabs.</li>
</ul>
<p>The full list is in the
<a href="https://github.com/Gaurav-Gosain/tuios/compare/v0.7.0...v0.8.0">changelog on GitHub</a>.</p>
<h2>Everything else</h2>
<p>The sections above cover what you will notice first. This is the rest, by
area.</p>
<h3>Agents and the daemon</h3>
<ul>
<li>A blocked agent's alert includes the question it asked. A state clears when
the agent exits back to its shell. <code>get-agent-state</code> and <code>list-agents</code> report
a confidence and whether the pane needs you, and <code>list-agents</code> reports
<code>human_unread</code>.</li>
<li>Every state has a word or a mark of its own, so colour is never the only
signal. The agents section header counts blocked and finished panes, and a
click on the count filters the list. <code>tuios agent-statusline</code> feeds a
harness's status line into the row.</li>
<li><code>tuios resume-agent</code> answers the resume item a restore puts in the Inbox.
<code>i</code> on a rail row opens that pane's mailbox. Mail lives in memory and ends
with the daemon.</li>
<li><code>wait-for agent-message --thread</code> and <code>read-agent-messages --thread</code> follow
one thread. Loop detection in <code>ask-agent</code> needs
<code>--from "$TUIOS_PANE_ID"</code>.</li>
<li><code>tuios popup --wait --capture-stdout</code> hands a picker's choice back to the
caller. The Inbox keys are in <code>[keybindings.inbox]</code>,
<code>[keybindings.inbox_peek]</code> and <code>[keybindings.mail]</code>.</li>
<li><code>tuios worktree ls</code> and <code>worktree rm</code> list and remove worktrees; a worktree
session is named <code>&#x3C;repo>-&#x3C;branch></code>. A fan on another machine can clone the
repository with <code>--clone</code>, which accepts only https, ssh and git URLs.
<code>tuios queue ls</code> and <code>queue rm</code> list and drop queued messages, and
<code>--confirm</code> takes the token <code>list-agents</code> prints for a write to several
panes.</li>
<li>With <code>hold_mail = true</code> in <code>[hosts.NAME]</code>, mail from that machine waits in
the Inbox for you to pass on with <code>p</code>.</li>
<li>A pane asked for more than it holds is refused with <code>forbidden</code>. A restored
session is marked restored in <code>tuios ls</code> until you first attach, and a window
whose shell will not start is dropped rather than restored empty.</li>
<li>Daemon panes honour <code>appearance.scrollback_lines</code> (the daemon kept 10,000
lines per pane whatever the file said) and <code>appearance.preferred_shell</code>.</li>
<li>Windows created in a daemon session now tile, where only windows the
attached client made used to be placed. BSP and master-stack tiles no longer
overlap when panes shrink.</li>
</ul>
<p><em><a href="https://tuios.dev/releases/v0-8-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<ul>
<li><code>tuios daemon --pprof</code> serves profiling data, and
<code>tuios set-config daemon.log_level messages</code> raises the log detail without a
restart. <code>kill-session</code> deletes a session's saved state, so a session you
killed on purpose never comes back.</li>
</ul>
<h3>Other machines</h3>
<ul>
<li><code>tuios hosts add</code> writes <code>[hosts.NAME]</code> in <code>config.toml</code>, and the daemon
follows the file, so no command here needs a restart. <code>tuios hosts test</code>
dials a machine now and says what it found, and where it looked for tuios
when it could not find it. <code>tuios hosts add NAME --tailnet</code> takes the
address from the tailnet machine of that name. An address is anything <code>ssh</code>
understands, and your <code>~/.ssh/config</code> aliases are offered in completion and
on the settings page, which has a Hosts section.</li>
<li><code>tuios attach --host</code> keeps a dropped session on screen and tries for three
minutes before it returns to the session it left. <code>--ssh</code> runs the far tuios
inside this one instead, for a host whose tuios is too old.</li>
<li>A remote pane that lost its link reads <code>[reconnecting] build:deploy</code>.</li>
<li><code>appearance.global_session = false</code> hides the <code>global</code> group in the rail.
Making a session asks which machine when more than one is reachable, from
<code>N</code>, the <code>+</code> at the start of the dock's session strip, or the palette.</li>
<li><code>local:</code> addresses a local session whose name contains a colon. Host
targets work for <code>list-windows</code>, <code>capture-pane</code>, <code>send-keys</code>, <code>send-text</code>,
<code>wait-for</code>, <code>focus-window</code>, <code>kill-session</code>, <code>session-info</code>,
<code>get-agent-state</code>, the mail verbs and the stash. <code>fan</code>, <code>worktree new</code> and
<code>start-agent</code> take a <code>HOST:SESSION</code> target too.</li>
</ul>
<h3>The rail and the dock</h3>
<ul>
<li>The rail is flat sections now, not a tree. <code>spacer</code> may repeat in
<code>appearance.sidebar.sections</code>, and the line above a pinned section can be
dragged to move the split. Rows scroll when truncated, and the collapsed
strip labels the row under the pointer.</li>
<li>A session with a generated name is labelled by its directory.
<code>appearance.session_border = true</code> tints every pane border with its
session's colour.</li>
<li><code>appearance.sidebar.folder_click</code> decides whether clicking a folder moves
the listing, sends a <code>cd</code> to the pane, or both.
<code>appearance.sidebar.file_delete = "permanent"</code> skips the trash. A file on
another filesystem is refused, and on Windows a delete is permanent and says
so. A pasted name that exists gains a number. <code>appearance.git_dirty</code> (on by
default) counts changed files.</li>
<li>The dock is a status line without powerline caps, set by a <code>[dock]</code> table:
<code>left</code>, <code>center</code> and <code>right</code> list components, <code>[dock.clock]</code> sets the time
format, and a <code>[dock.custom.NAME]</code> entry runs a shell command and shows what
it prints, killed with its whole process tree at its timeout. Workspace pills
can be dragged into a display order without renumbering the workspaces.</li>
</ul>
<h3>Tiling and the mouse</h3>
<ul>
<li>A pane can be floated out of a tiled layout, or pinned so it follows you
across workspaces. "All windows" in the palette searches every window in
every workspace.</li>
<li><code>appearance.zoom_animation</code> turns the zoom slide off, and a tiled pane's
title bar can carry a zoom button (<code>appearance.window_button_zoom</code>).</li>
<li>In the scrolling layout, <code>appearance.scroll_column_max</code> (20 to 100, default
90) lets a column fill the screen, and <code>appearance.niri_click_reveals</code> and
<code>appearance.niri_hover_reveals</code> bring the whole column on screen. Column
widths survive a session switch
(<a href="https://tuios.dev/blog/a-session-switch-forgot-my-column-widths">the post</a>).
<code>appearance.niri_scroll_cells</code> (default 8) sets how far one scroll moves the
strip, and sideways trackpad drift no longer walks it.</li>
<li><code>tuios popup</code> takes <code>--width</code> and <code>--height</code> in cells or percent (default
80% and 60%), and esc in window mode closes the focused popup.
<code>appearance.new_window_inherit_cwd = false</code> opens new windows in your home
directory instead.</li>
<li>Turning tiling on after floating brings back the arrangement you had.
Floating windows no longer draw over the clock or the log viewer, and
raising one no longer reshuffles the others.</li>
<li>A click that only focuses a pane no longer resizes it, and a drag that puts
a pane back where it was resizes nothing, so your shell no longer reprints
its prompt.</li>
<li><code>appearance.links</code> picks which links respond: <code>off</code>, <code>marked</code> for OSC 8
only, or <code>all</code> (the default), which adds bare URLs. A <code>file://</code> directory
opens in the rail's file view.</li>
</ul>
<h3>Keys</h3>
<ul>
<li>The palette and the launcher sit in a <code>[keybindings.global]</code> section that
is read in every mode, and any action can be bound there.</li>
<li>In the keybind manager, <code>ctrl+x</code> on a row frees that key everywhere, and
<code>tuios keybinds unbind</code> removes one action from one key. Each finding says
how it knows: <code>certain</code> from tuios's own routing, <code>observed</code> from a live
pane, or <code>reference</code> from a list of program defaults.</li>
<li>The launcher shows names and icons from desktop entries where the platform
has them. All four search boxes in tuios share one fuzzy matcher.</li>
<li><code>appearance.auto_enter_terminal_on_focus</code> can be <code>off</code> (the default),
<code>targeted</code> (focus by selection and arrows) or <code>all</code> (including Tab).</li>
<li>The prefix arrows walk panes, and <code>ctrl+b a</code> opens the launcher. These work
on macOS with no terminal settings. Keybindings also accept the lock keys
and the other keys Bubble Tea names under the Kitty protocol.</li>
</ul>
<h3>Look and feel</h3>
<ul>
<li><code>tuios list-themes</code> lists the built-in themes and your themes directory. An
imported theme works without a restart, switching theme recolours every open
pane in place, and a theme can describe itself: colours under the contrast
floor are named.</li>
<li>A theme's <code>chrome</code> object takes <code>accent</code>, <code>accent_bright</code>, <code>success</code>,
<code>warning</code>, <code>error</code> and <code>info</code>, and <code>chrome.surface</code> sets the colour dialogs
are drawn on.</li>
<li>A custom glyph set is a file that can inherit from a built-in one, and every
glyph has its own ASCII fallback.</li>
<li>The colour picker has a hue strip, a shades grid, HSL and RGB sliders, a hex
field, a harmony wheel, and the theme's own colours as slots that follow the
theme.</li>
<li>The backgrounds are <code>appearance.pane_background</code>, <code>desktop_background</code>,
<code>window_chrome_background</code>, <code>dock_background</code> and
<code>appearance.sidebar.background</code>. Only cells with no colour of their own are
painted, a program that asks for the background colour is told the painted
one, screenshots use it, and the settings page has a Backgrounds tab.</li>
<li>The scrollbar has two styles: a single stroke in the pane's own ink, or a
track with a half-cell thumb.</li>
<li><code>appearance.selection.flash</code> turns the copy flash off, and <code>flash_ms</code>,
<code>flash_color</code> and <code>flash_style</code> (<code>diagonal</code>, <code>diagonal-reverse</code>,
<code>horizontal</code>, <code>vertical</code>) tune it.</li>
<li><code>appearance.zen_mode</code> hides unfocused borders; content never shifts.</li>
<li>The screen saver starts after <code>screensaver.idle_minutes</code>, with
<code>screensaver.effect</code> or <code>random</code>. Effects run at the right speed at any frame
rate, and on an unthemed session the saver asks the terminal for its palette.</li>
<li>The keycast coalesces repeats and remembers whether it is on.</li>
</ul>
<p><em><a href="https://tuios.dev/releases/v0-8-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<ul>
<li>Empty lists say why they are empty and show one key. A loading state waits
half a second before it shows, so a fast load never flashes.</li>
</ul>
<h3>Graphics and the web client</h3>
<ul>
<li>On macOS, <code>tuios screenshot</code> finds your fonts without fontconfig, including
fonts inside <code>.ttc</code> collections, so Nerd Font icons draw.
<code>tuios screenshot -w build</code> captures a window by name from a script.</li>
<li>Kitty graphics over SSH take the client's capabilities from the connection:
<code>TERM</code>, the forwarded environment and the pixel size it reports. A flood of
graphics is paced so it cannot starve the keyboard, and an image in a pane's
last rows no longer scrolls the whole screen up.</li>
<li>Unicode placeholders need a host that supports them (kitty, Ghostty,
WezTerm), so not tuios-web. <code>appearance.kitty_placeholders</code> forces the
choice.</li>
<li>The web client's text shaping uses sip's WebGL renderer with HarfBuzz.
Grapheme widths match a reference terminal, and a freeze where synchronized
output was left on is fixed.</li>
</ul>
<p><em><a href="https://tuios.dev/releases/v0-8-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<ul>
<li><code>tuios-web cert</code> inspects or replaces the certificate <code>--auto-tls</code> made.
Settings changed from a browser apply to that session only, instead of
writing the server's config file. The tab says tuios and has a favicon, and
the QUIC and WebTransport libraries moved past several reported
vulnerabilities.</li>
</ul>
<h3>Project tapes and startup</h3>
<p>A tape runs commands, so nothing happens until you have read it. The review
dialog shows the whole file, and you choose Run once, Trust and run, or Never.
By default a dock badge and a notification say a tape is there. <code>auto_review</code>
opens the review on detection, and <code>autorun = "auto"</code> runs a tape you trusted
and have not edited since. Running one builds a session named after the
project.</p>
<p><em><a href="https://tuios.dev/releases/v0-8-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<p><code>startup.open_default_window</code>, <code>startup.tiled</code> and
<code>startup.start_in_terminal_mode</code> remove the steps every session started with.
With all three on, tuios opens tiled with one terminal and your next key goes
to the shell. Startup asks the terminal everything in one round trip, which is
where the 566ms to 68ms came from.</p>
<p><em><a href="https://tuios.dev/releases/v0-8-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<p>The settings page reopens on the tab, row and search you left, 1 to 9 pick a
tab, and <code>tuios list-options --search</code> runs its search from a shell.</p>
<h3>Scripting</h3>
<ul>
<li>One registry backs <code>set-option</code>, <code>get-option</code> and <code>list-options</code>. It fixed a
dozen settings, from border style to the leader key, that were saved and
then read back as defaults, and a boolean turned off that could not be saved.</li>
<li>Config reload works with editors that save by renaming, such as vim.</li>
<li>A failing hook logs its exit code and the tail of its stderr.</li>
<li>The crash report has the build, terminal, layout and last actions. <code>c</code>
copies it and <code>g</code> opens a prefilled issue. It never includes pane contents,
titles, paths or session names.</li>
<li><code>tuios send-keys</code> takes <code>--repeat</code> and no longer pulls a pane you scrolled
back to the bottom. <code>tuios new-window --print-id</code> prints the new window's
id.</li>
<li><code>tuios stash put</code> and <code>stash get</code> print only the path, so
<code>path=$(tuios stash put FILE)</code> works.</li>
</ul>
<h3>The terminal emulator</h3>
<ul>
<li>Under <code>TERM=screen</code>, <code>linux</code> or <code>vt100</code>, SO and SI were unreachable, which is
why box drawing came out as <code>lqk</code>.</li>
<li>A mode map read without its lock, and two captures of one busy pane, could
each crash the daemon.</li>
<li>Insert mode was recorded but ignored, REP repeated the wrong character, and
a wide character cut at a margin left half of itself behind.</li>
<li>A single shift (SS2, SS3) before a multi-byte character leaked into the next
one, and invalid bytes in window titles are now dropped.</li>
<li>Underline and other attributes were dropped on the focused pane's render
path.</li>
<li>DECRQM reported modes 47, 1016 and 2048 as unknown.</li>
<li>On the ghostty backend, grapheme clustering was off, so a family emoji took
eight columns, and <code>scrollback_lines</code> did not hold: a pane asked for 10,000
lines kept about 400 at 207 columns.</li>
<li>A table of links and clusters in the scrollback was never pruned, so a pane
printing a link on every line grew for its whole life.</li>
<li>The first version of the differential suite passed while the ghostty
backend painted <code>ls</code> on hot pink, which is
<a href="https://tuios.dev/blog/my-differential-tests-passed-and-the-screen-was-pink">its own post</a>.
Where the backends still disagree, the difference is pinned as a known
divergence.</li>
</ul>
<h3>Speed and memory</h3>
<ul>
<li>The render ticker runs at <code>max_fps</code>, which at the default of 60 took an idle
client from 1.0% to 0.6% of a core.</li>
<li>A keystroke over the socket went from 4,009ns and four writes to 967ns and
one.</li>
<li>A pane that falls more than 4MiB behind drops to catch-up rate until it
recovers, and a flooding pane sends at most one frame per millisecond once
it has sent 4KB in it, instead of one frame per PTY read.</li>
<li>A workspace switch asks only for rows the client does not have: at four
panes, 11.5MB of encoding became 0.6MB.</li>
<li>Drawing a pane's frame went from 6.53ms to 1.58ms when dirty and from
3.51ms to 62.7us when cached. The rail's rows went from 82,000ns and 178
allocations per frame to 288ns and none.</li>
<li>Moving the pointer over plain text no longer composes a frame per cell. A
truecolor repaint allocates a quarter of what it did, and scrolling short
lines costs 65 to 79 percent less CPU.</li>
<li>The linux/amd64 binary went from 31,559,840 bytes to 25,231,520. The review's
diff highlighter carries 88 of chroma's 279 lexers, tailnet discovery runs
<code>tailscale status --json</code> instead of linking tailscale's client, and
<code>tuios update</code> fetches through <code>curl</code>, which took <code>net/http</code> and
<code>crypto/tls</code> out of the binary.</li>
<li>Scrollback is stored as text with styles marked where they change: a
175-character line went from 4,864 bytes to 216. An empty pane allocates a
row only when something is printed on it, and the alternate screen is built
on first use. Eight empty panes went from 47.5MiB of heap to 14.9MiB.</li>
</ul>
<h3>More fixes</h3>
<ul>
<li>Ctrl+P opens the palette even when the terminal reports Num Lock in the key
event.</li>
<li>Quitting a session says "Killed", not "detached", and names the session.</li>
<li>A grapheme cluster split across two writes renders as one.</li>
<li>Programs in tuios are told graphics forwarding is available, so image tools
stop falling back to blocks.</li>
<li>The log viewer's copy keys (<code>E</code> for errors, <code>A</code> for all) work.</li>
<li>Help opened from the leader starts at the top, and <code>q</code> closes it outside a
search and can be typed inside one.</li>
<li>Mouse scroll speed and the window title format are configurable.</li>
<li>A recorded tape typed escapes such as <code>‍</code> as letters on playback.</li>
<li>PNG screenshots no longer draw a faint notch in every row of a pane border,
and draw the Enter key glyph instead of an empty box. Box drawing is aligned
to the pixel grid.</li>
<li><code>golang.org/x/crypto</code> moved past a denial of service the SSH server reached.</li>
<li>The unit tests went from 4,282 test functions to 2,870, keeping only the ones
that catch a bug the end-to-end suite misses.</li>
</ul>
<h2>Upgrading from v0.7.0</h2>
<p>Most of these need nothing from you. The ones that do say what to change.
tuios never rewrites your config file: old keys that still mean something are
read and translated when the file loads.</p>
<h3>Restart the daemon</h3>
<p>The wire protocol is version 3, and a version 2 daemon is refused with a
message that says which side is newer. Run <code>tuios kill-server</code> and start tuios
again. This ends every session the v0.7.0 daemon holds: v0.7.0 saves nothing,
so its layouts, window names and working directories are lost along with the
programs in its panes. Note what you want to keep before you run it. From
v0.8.0 on, a daemon restart brings the layout back. The JSON verb protocol
stays at version 1.</p>
<h3>Turn on the daemon</h3>
<p>A fresh install uses the daemon and starts tiled. An existing config file does
not: <code>[startup]</code> has no default for keys the file leaves out, so a file that
does not name <code>daemon</code> and <code>tiled</code> reads them as false, and tuios keeps
running standalone and floating, with no restore. To get the new behaviour,
add this to <code>config.toml</code>:</p>
<pre><code class="language-toml">[startup]
daemon = true
tiled = true
</code></pre>
<p><code>tuios --standalone</code> or <code>TUIOS_NO_DAEMON=1</code> runs without the daemon. If the
daemon will not start, a bare <code>tuios</code> runs standalone for that run and says
so.</p>
<h3>Defaults</h3>
<p>These defaults changed. A key your config file sets keeps its value, so what
you get depends on what the file names. The last column is what a config file
written by v0.7.0's first run gets.</p>
<table>
<thead>
<tr>
<th>Setting</th>
<th>Key</th>
<th>v0.8.0 default</th>
<th>With a v0.7.0 config file</th>
</tr>
</thead>
<tbody>
<tr>
<td>Daemon</td>
<td><code>startup.daemon</code></td>
<td><code>true</code></td>
<td><code>false</code></td>
</tr>
<tr>
<td>Start tiled</td>
<td><code>startup.tiled</code></td>
<td><code>true</code></td>
<td><code>false</code></td>
</tr>
<tr>
<td>Rail</td>
<td><code>appearance.sidebar.enabled</code>, <code>position</code>, <code>width</code></td>
<td>on, <code>right</code>, <code>24</code></td>
<td>on, <code>right</code>, <code>24</code></td>
</tr>
<tr>
<td>Dock</td>
<td><code>appearance.dockbar_position</code></td>
<td><code>top</code></td>
<td><code>bottom</code></td>
</tr>
<tr>
<td>Window titles</td>
<td><code>appearance.window_title_position</code></td>
<td><code>top</code></td>
<td><code>top</code></td>
</tr>
<tr>
<td>Zoom</td>
<td><code>appearance.zoom_size</code></td>
<td><code>95</code></td>
<td><code>95</code></td>
</tr>
<tr>
<td>Click to type</td>
<td><code>appearance.click_to_type</code></td>
<td><code>double</code></td>
<td><code>double</code></td>
</tr>
<tr>
<td>Scrollbar</td>
<td><code>appearance.scrollbar.style</code></td>
<td><code>track</code></td>
<td><code>track</code></td>
</tr>
<tr>
<td>Window controls</td>
<td><code>appearance.window_button_style</code>, <code>window_button_position</code></td>
<td><code>dots</code>, <code>left</code></td>
<td><code>dots</code>, <code>left</code></td>
</tr>
<tr>
<td>Motion</td>
<td><code>appearance.motion</code></td>
<td><code>full</code></td>
<td><code>full</code>, or <code>none</code> if the file sets <code>animations_enabled = false</code></td>
</tr>
</tbody>
</table>
<p>To keep the v0.7.0 look:</p>
<pre><code class="language-toml">[appearance]
dockbar_position = "bottom"
window_title_position = "bottom"
zoom_size = 100
click_to_type = "single"
window_button_style = "pill"
window_button_position = "right"

[appearance.sidebar]
enabled = false
</code></pre>
<p>Each line also works on its own, from the settings page (<code>ctrl+b ,</code>), or live
with <code>tuios set-config</code>, for example <code>tuios set-config zoom_size 100</code>.
<code>ctrl+b b</code> shows and hides the rail at any time.</p>
<h3>Keys and mouse</h3>
<ul>
<li>
<p><strong>Plain <code>ctrl+v</code> goes to the pane</strong>, as 0x16, so vim's visual block works.
Paste from the host clipboard is <code>ctrl+shift+v</code>, <code>super+v</code> or
<code>shift+super+v</code>. To paste on <code>ctrl+v</code> again, bind it:</p>
<pre><code class="language-toml">[keybindings.terminal_mode]
terminal_paste_host = ["ctrl+v", "ctrl+shift+v", "super+v", "shift+super+v"]
</code></pre>
</li>
<li>
<p><strong><code>alt+arrows</code> move focus between panes</strong> in terminal mode. They used to
reach the shell, where readline, fish and zsh use <code>alt+left</code> and <code>alt+right</code>
to move by word. To give one back, run <code>tuios keybinds free alt+left</code>, or set
the action to an empty list:</p>
<pre><code class="language-toml">[keybindings.terminal_mode]
terminal_focus_left = []
terminal_focus_right = []
</code></pre>
<p><code>ctrl+b</code> then the arrows still move focus.</p>
</li>
<li>
<p><strong><code>alt+n</code> and <code>alt+p</code></strong> move to the next and previous window in terminal
mode, on a fresh config. Free them the same way if your shell uses them.</p>
</li>
<li>
<p><strong><code>esc</code> after the prefix exits prefix mode.</strong> It used to detach. Detach is
<code>ctrl+b d</code>. A config with the old binding is migrated on load.</p>
</li>
<li>
<p><strong><code>ctrl+b ,</code> opens settings.</strong> Rename window is <code>ctrl+b r</code>.</p>
</li>
<li>
<p><strong><code>ctrl+b M</code> opens the Inbox</strong> on its mail. The mailbox is <code>m</code> from there.</p>
</li>
<li>
<p><strong>Multi-select is <code>ctrl+shift+click</code>.</strong> It used to be <code>ctrl+click</code>, which now
grabs the window: <code>ctrl</code> and a left drag moves it.</p>
</li>
<li>
<p><strong>A left drag in a pane selects text</strong> and copies it on release. It used to
move the window. <code>appearance.copy_on_select = false</code> stops the copy.</p>
</li>
<li>
<p><strong>A double click enters terminal mode</strong>, where a single click did.
<code>appearance.click_to_type = "single"</code> brings that back.</p>
</li>
<li>
<p><strong>The mouse wheel scrolls the pane</strong> and no longer enters copy mode. Typing
returns to the live screen.</p>
</li>
<li>
<p><strong>Right-click</strong> in window mode opens the pane menu, and a right drag resizes.
In terminal mode the right button belongs to the pane: ctrl or shift and a
right-click opens the menu, or set <code>appearance.right_click_opens_menu = true</code>.</p>
</li>
<li>
<p><strong>Window-mode digits 1 to 4 select windows.</strong> Corner snap moved to
<code>ctrl+b L</code> then 1 to 4. The old default bindings are migrated on load. With
tiling on, <code>h</code> and <code>l</code> focus the pane on that side.</p>
</li>
<li>
<p><strong><code>q</code> and <code>ctrl+b q</code> open a quit menu</strong>, with detach as the default row.</p>
</li>
<li>
<p>In the layout picker, delete moved from <code>d</code> to <code>ctrl+d</code>.</p>
</li>
<li>
<p>Notifications moved from a top-right toast to the dock. Info stays 6
seconds, warnings 8, and errors until dismissed. <code>[notifications]</code> sets the
durations.</p>
</li>
</ul>
<h3>Scripts</h3>
<ul>
<li><strong><code>TERM_PROGRAM</code> is not always <code>TUIOS</code>.</strong> It is <code>ghostty</code> when kitty
graphics are forwarded, <code>WezTerm</code> when sixel is, and <code>WarpTerminal</code> in a pane
that starts Codex directly, so programs turn on what they can do. A shell
pane with none of these is still <code>TUIOS</code>. A script that checks for tuios
should read <code>TUIOS_ENV</code> (or <code>TUIOS_PANE_ID</code>).</li>
<li><strong><code>TMUX</code> and <code>TMUX_PANE</code> are not passed to panes.</strong> A tuios started inside
tmux used to hand them on, so programs thought they ran in tmux. A pane on
another machine gets <code>TUIOS_SESSION_REMOTE</code> instead of <code>TUIOS_SESSION</code>.</li>
<li><strong><code>tuios ls</code> with no daemon exits 3.</strong> It lists the sessions saved on disk,
marked as saved. It used to print an empty list and exit 0.</li>
<li><strong>Appearance flags are only accepted by commands that draw</strong>: a bare
<code>tuios</code>, <code>attach</code>, <code>new</code>, <code>ssh</code> and tape playback. Elsewhere they are an
error, so <code>tuios ls --theme x</code> now fails. Drop them from other commands.</li>
<li><strong>Verbs refuse unknown input.</strong> An unknown parameter, an unknown
<code>set-option</code> path, a bad colour, an unknown theme and an unknown
<code>run-command</code> name are errors instead of being ignored.</li>
<li><strong><code>TUIOS_SOCKET</code> reports the pane's daemon; it does not choose one.</strong> A
script that pointed it at a fresh path to get a daemon of its own used to
create its sessions in yours. A command now refuses when <code>TUIOS_SOCKET</code>
names a socket where no daemon listens. To run a separate daemon, set
<code>XDG_RUNTIME_DIR</code> and <code>XDG_STATE_HOME</code>.</li>
<li><strong>Calls from a pane are checked against its grants.</strong> With no
<code>[agents.permissions]</code> table a pane holds <code>admin</code>, so nothing changes until
you narrow it. A pane can never send as <code>human</code>.</li>
<li><code>ask-agent</code> and <code>fan</code> send the prompt as a bracketed paste and one carriage
return. <code>ask-agent</code> refuses an agent blocked on a prompt unless you pass
<code>--allow-blocked</code>.</li>
<li><code>tuios attach</code> with no daemon starts one instead of refusing.</li>
<li><code>tuios layout export</code> prints a tape script, not JSON.</li>
</ul>
<h3>Config</h3>
<ul>
<li><strong><code>animations_enabled</code> is replaced by <code>appearance.motion</code>.</strong> An old file
with <code>animations_enabled = false</code> reads as <code>motion = "none"</code>, and <code>true</code>
changes nothing. Where both are set, <code>motion</code> wins. Move to the new key:
<code>motion = "none"</code>, <code>"basic"</code> or <code>"full"</code>.</li>
<li><strong>Removed keys:</strong> <code>daemon.default_codec</code> (the JSON wire codec is gone),
<code>daemon.socket_path</code> (it was never honoured: the socket follows
<code>XDG_RUNTIME_DIR</code>) and <code>appearance.focus_follows_mouse_in_terminal</code>. They are
ignored. Delete them.</li>
<li><strong>Removed flag:</strong> <code>tuios tape play --visible</code> (<code>-v</code>), which nothing read.
Drop it. The hidden <code>tuios man</code> command is gone.</li>
<li><strong>Removed actions:</strong> <code>nav_up</code>, <code>nav_down</code>, <code>nav_left</code>, <code>nav_right</code>,
<code>toggle_showkeys</code> and <code>prefix_logs</code>. The top-left key-events overlay is
replaced by the keycast.</li>
<li><code>appearance.max_fps</code> tops out at 120, the renderer's own ceiling.</li>
<li>Selection colours are settings under <code>[appearance.selection]</code>: grey
selection, amber search, cyan copy cursor, not bold.
<code>appearance.selection.bold = true</code> brings bold back.</li>
<li>The <code>colorshift</code> screen saver effect reads as <code>random</code>.</li>
<li><strong>Hooks moved to the daemon:</strong> <code>after-new-window</code>, <code>after-close-window</code>,
<code>after-focus-change</code>, <code>after-workspace-switch</code> and <code>after-agent-state</code> run
with the daemon's environment and fire once, not once per client.
<code>after-attach</code>, <code>after-detach</code>, <code>after-resize</code> and <code>after-layout-change</code>
stay in the client, and <code>after-detach</code> now also fires when an SSH
connection or a browser tab goes away.</li>
<li><strong>Linked machines have a policy.</strong> A machine linked to this one gets what
<code>[hosts.NAME]</code> allows, by default everything but answering prompts and
approvals.</li>
</ul>
<p>If you ran a build from main during this cycle, a few more apply. v0.7.0 had
none of these keys:</p>
<ul>
<li><code>appearance.separator_style</code> is removed. Delete it.</li>
<li>Sidebar settings moved into an <code>[appearance.sidebar]</code> table. The old
<code>appearance.sidebar_*</code> keys are still read, and the table wins.</li>
<li><code>appearance.sidebar.show_windows</code> and <code>show_agents</code> are folded into
<code>appearance.sidebar.sections</code> when the config loads. Edit <code>sections</code>
instead, for example <code>sections = 'sessions,terminals,files,git,agents'</code>.</li>
<li><strong>Reinstall the agent integrations.</strong> Copilot, Cursor Agent and Qwen Code
now report their full state, and opencode, Kilo, Amp and Pi hooks changed.
<code>tuios integration status</code> marks an old install as out of date. Run
<code>tuios integration install --all</code>.</li>
</ul>
<p><code>appearance.gap</code> is not removed: an early <code>gap</code> key that did nothing became
the working <code>appearance.gap</code>.</p>
<h3>SSH</h3>
<ul>
<li><strong><code>tuios ssh</code> checks keys.</strong> It admits the public keys in
<code>~/.config/tuios/authorized_keys</code>, or in <code>~/.ssh/authorized_keys</code> when the
first file is absent. <code>--authorized-keys FILE</code> names another file. Without
keys, a loopback address still runs unauthenticated with a warning, and any
other address is refused. <code>--no-auth</code> opens it on a network you trust.</li>
<li>A connection that names no session gets one called <code>ssh-session</code> when
several exist, instead of the first one listed. To reach a session, name it
in the username (<code>ssh api@host -p 2222</code>) or run <code>ssh host -p 2222 -t attach api</code>. The usernames <code>tuios</code>, <code>root</code> and <code>anonymous</code> do not count as a name.</li>
<li>The SSH session picker is removed. v0.7.0 never showed it.</li>
</ul>
<h3>Agents</h3>
<ul>
<li>Agent state reporting is new in this release. Run
<code>tuios integration install --all</code> to install the hooks for every harness you
have, then <code>tuios doctor agents</code>.</li>
<li><strong>The Claude Code hook map changed</strong> for anyone who installed hooks from
main. <code>SessionStart</code> means idle, <code>Notification</code> is read by its type,
<code>StopFailure</code> means errored, and <code>SessionEnd</code> sets nothing. The hooks call
<code>tuios agent-hook</code>, and the old Python shim only wraps it.</li>
<li>Your own harness manifests: an idle screen rule needs a <code>prompt_box</code> region
or a regex. <code>argv_path</code> matches whole path components, and only in the
script an interpreter runs, not in any argument. A manifest that matches on
a bare name shorter than five characters must add a <code>[detect.require]</code> block
(for example <code>exe_base = ["node"]</code>) or it is refused. See
<a href="https://tuios.dev/docs/agents">Agents</a>.</li>
</ul>
<h3>Terminal behaviour</h3>
<ul>
<li>ED 3 (<code>CSI 3 J</code>) now clears only the scrollback, as in other terminals. It
used to clear the screen too.</li>
<li>Entering the alternate screen (modes 1049 and 1047) keeps the cursor where
it is. It used to move it to the top left.</li>
<li>With no theme, a program that asks for the terminal's colours (OSC 4, 10 and
11) gets your terminal's own answers instead of fixed black and white.</li>
</ul>
<h3>Embedders</h3>
<p><code>pkg/tuios</code> takes a <code>config.Settings</code> per client instead of package globals,
many <code>app.OS</code> exports are gone, <code>pkg/tfx</code> is now the <code>tuiffects</code> module, and
the SSH module is <code>charm.land/ssh</code>.</p>
<h3>Known issues</h3>
<ul>
<li>Windows in a session made by <code>tuios fan</code> open floating instead of tiled.
<code>t</code> in window mode tiles them.</li>
<li>In a pane whose shell does not send OSC 7, the rail's files and git sections
stop following the pane's directory after <code>tuios set-window --name</code> renames
the pane. A shell that sends OSC 7 is not affected.</li>
<li><code>tuios update</code> on a Homebrew install suggests <code>brew upgrade --cask tuios</code>.
That is right for the tap's cask; for the formula in Homebrew core, run
<code>brew upgrade tuios</code>.</li>
</ul>
<h2>Numbers</h2>
<ul>
<li>2,411 commits between v0.7.0 (29 March 2026) and the release, 2,078 of them
not merges. v0.7.0 had 158, 157 of them not merges.</li>
<li>653 fixes, 396 features, 412 test commits, 152 docs commits and 91
performance commits, by their conventional-commit prefix.</li>
<li>2,429 files changed: 466,372 lines added and 39,887 removed.</li>
<li>97 JSON verbs, 167 options you can set live, 23 agent harness manifests, 18
harness integrations, 343 built-in themes, 36 screen saver effects, 4 glyph
sets and 3 tilers.</li>
<li>30 engineering posts on the <a href="https://tuios.dev/blog">blog</a> since June.</li>
</ul>
<h2>Thanks</h2>
<p>Eight people besides me sent changes in this release:</p>
<ul>
<li><strong>Sebastian Wagner</strong> (<a href="https://github.com/SebaWag">@SebaWag</a>): percentage
resize (<a href="https://github.com/Gaurav-Gosain/tuios/issues/29">#29</a>), zen mode,
the dock's workspace tab format, <code>appearance.right_click_opens_menu</code>, the
native clipboard fallback for SSH and VTE terminals, the reattach replay fix,
resolved colours in <code>capture-pane</code>, and the Nix package repairs.</li>
<li><strong>Siriwat Uamngamsup</strong>: entering terminal mode when keyboard focus moves to
another pane (<code>appearance.auto_enter_terminal_on_focus</code>).</li>
<li><strong>Iain</strong>: <code>list-options</code> grouped by section, and the <code>--list-themes</code> warning
fix.</li>
<li><strong>Ronan Arraes Jardim Chagas</strong>: <code>chrome.surface</code> in theme files.</li>
<li><strong>Masshiro</strong>: Home and End under application cursor keys
(<a href="https://github.com/Gaurav-Gosain/tuios/pull/193">#193</a>).</li>
<li><strong><a href="https://github.com/actes2">@actes2</a></strong>: a resize floor so a vanishing
display cannot panic.</li>
<li><strong><a href="https://github.com/ethanhawkes-gif">@ethanhawkes-gif</a></strong>: a panic on a
wrapped nil colour.</li>
<li><strong><a href="https://github.com/FaintFlower">@FaintFlower</a></strong>: the README star chart.</li>
</ul>
<p>And thank you to everyone who filed an issue, tried a build from main, or told
me what broke.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.7.0</title>
      <link>https://tuios.dev/releases/v0-7-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-7-0</guid>
      <pubDate>Sun, 29 Mar 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>Video playback in a pane, the kitty keyboard protocol, a rebuilt copy mode with a real scrollbar, a command palette, and the hundred fixes it took to make graphics passthrough honest.</description>
      <content:encoded><![CDATA[<p>157 commits between v0.6.0 and v0.7.0: 34 features and over a hundred fixes.
The terminal inside tuios now speaks the protocols real programs use:</p>
<ul>
<li>Video plays in a pane.</li>
<li>fish 4.x's kitty keyboard handshake works.</li>
<li>Copy mode has a scrollbar you can grab.</li>
<li>A command palette lists every action.</li>
</ul>
<p>Most of the fixes are the cost of passing another terminal's protocol through a
multiplexer: clipping, positioning, flicker, and the gap between what a spec
says and what mpv sends.</p>
<h2>Changed behaviour</h2>
<ul>
<li>The mouse wheel now enters copy mode. The separate scrollback mode, which
could scroll but not select, is gone.</li>
<li>The dock's clock, CPU and RAM meters are off by default, and are only polled
when shown.</li>
<li>A new <code>--confirm-quit</code> flag and <code>confirm_quit</code> option always ask before
quitting.</li>
</ul>
<h2>Video playback</h2>
<p><code>mpv --vo=kitty</code> plays video in a tuios pane, and so does
<a href="https://github.com/Gaurav-Gosain/youterm">youterm</a>. Shared memory and base64
modes both work. Use <code>--vo-kitty-use-shm=yes</code>: it sends a file reference per
frame instead of streaming megabytes of pixels through the terminal.</p>
<p>Video is the hardest case for graphics passthrough, and most of the fixes were
here:</p>
<ul>
<li>mpv marks every frame "more data coming" and never sends the final-chunk
marker the protocol says to wait for, so passthrough that worked for static
images waited forever.</li>
<li>Each frame used to get a new image ID, forcing a delete and replace with a
visible flash. Frames now reuse the host's image ID, so the terminal swaps
the data in place.</li>
<li>File-based frames are forwarded as a path instead of being read, base64
encoded and chunked, which saves about 4MB of allocation per frame at 30fps.</li>
<li>All graphics output is wrapped in synchronized updates and flushed with the
render cycle. Text and graphics arriving as two unsynchronized streams caused
the tearing.</li>
</ul>
<p>Static images got the same care: icat and yazi previews clip at the viewport,
hide when their window leaves the screen, and follow the window during a drag.</p>
<h2>The keyboard protocol shells expect</h2>
<p>The VT emulator implements the kitty keyboard protocol: the full push, pop and
query stack, with keys sent in CSI u encoding when a program has the protocol
on. fish 4.x turns it on at startup, and before this release capital letters
arrived as escape sequences fish ignored. As the spec says, shifted printable
keys now send their text, and CSI u is kept for real modifier combinations.</p>
<p>The same work added:</p>
<ul>
<li>OSC 4 palette queries and OSC 52 clipboard.</li>
<li>Modes 2026 (synchronized output) and 2027 (unicode core).</li>
<li>Sixel in the DA1 reply.</li>
<li>OSC 66 text sizing, as an experimental passthrough (see
<a href="https://tuios.dev/releases/v0-7-0#known-limitations">Known limitations</a>).</li>
</ul>
<h2>Copy mode</h2>
<ul>
<li>The mouse wheel drops you into copy mode, so scrolling up and selecting are
one gesture. It has full vim navigation, visual and visual-line selection,
search and yank.</li>
<li>The border is a scrollbar, drawn in the theme's border colours and sized to
the content. Click it to jump and drag it to scroll.</li>
<li>Dragging a selection past the edge of the pane keeps scrolling on a timer,
so the selection keeps growing while the mouse is still.</li>
</ul>
<p>A new scrollback browser splits your history into command blocks using OSC 133
markers, with a regex fallback for shells that do not emit them. Each block is
a command and its output, navigable with vim keys, and you can yank JSON
fragments and file paths out of the output. fish and a configured starship both
emit OSC 133.</p>
<p><em><a href="https://tuios.dev/releases/v0-7-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<h2>Command palette, sessions and layouts</h2>
<ul>
<li><strong>Command palette</strong> on <code>Ctrl+P</code>: every tuios action, fuzzy-searched, with its
key shown beside it. A match on the name ranks above a match on the
category. It floats at the top of the screen and works in both modes.</li>
<li><strong>Session switcher</strong> on <code>prefix+S</code> lists daemon sessions the same way.</li>
<li><strong>Layout templates</strong> save the BSP tree, each window's working directory (read
from <code>/proc</code>), startup commands, and the tiling scheme. Positions scale when
you load a template on a different screen size. Loading moves existing
windows into place instead of killing them, and minimizes extras. The CLI is
<code>tuios layout list</code>, <code>delete</code>, <code>dir</code> and <code>export</code>, and <code>export</code> turns a
template into a tape script. The layout submenu is on <code>Ctrl+B L</code>.</li>
<li><strong>Zoom</strong> on <code>z</code> fills the screen with the focused pane. Press it again to
restore. The dock shows a Z while zoomed.</li>
<li><strong>Shared borders.</strong> With <code>--shared-borders</code>, tiled windows are drawn without
borders and a single line with proper junctions separates them, which saves
two columns and two rows per split. It is opt-in because it took several
attempts: the feature was reverted and reimplemented three times before the
separator overlay stuck.</li>
<li><strong>Smart split</strong> picks the split direction from the focused pane's shape. It
is opt-in because as a default it made narrow slices, so spiral stays the
default.</li>
</ul>
<p><em><a href="https://tuios.dev/releases/v0-7-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<h2>Faster underneath</h2>
<ul>
<li>Rendering is driven by PTY output instead of a tick. The tick remains only
for animations and tape playback, and slows to an idle rate when nothing
moves. With the dock meters off by default, idle CPU is near zero.</li>
<li>Unfocused windows without a selection take a fast path that skips per-cell
styling. Windows on other workspaces skip render work, and tuios-web and SSH
clients do not even receive their output until you switch to them.</li>
<li>Base64 image data passes through without a decode and re-encode, which saves
about 8MB of memory traffic per 4MB image. <code>/dev/tty</code> is opened once instead
of per frame, and only placements that moved are placed again.</li>
<li>tuios moved to the stable Charm v2 releases: bubbletea, lipgloss, wish and
log.</li>
</ul>
<h2>Fixed</h2>
<p>Most graphics fixes are described above. The rest, grouped:</p>
<p><strong>Daemon mode</strong></p>
<ul>
<li>The daemon's emulator dropped kitty graphics capability queries, so icat and
chafa fell back to blocks. The daemon now answers them.</li>
<li>PTY sizes sync on reattach instead of keeping the previous client's size.</li>
<li>The client sends its pixel size and graphics capabilities to the daemon at
hello.</li>
<li>The subscriber buffer is 16 times larger, so video frames survive the socket
from daemon to client.</li>
</ul>
<p><strong>Input and mouse</strong></p>
<ul>
<li>Mouse motion is only sent to programs that asked for it. kakoune got
hundreds of unrequested motion events a second
(<a href="https://github.com/Gaurav-Gosain/tuios/issues/78">#78</a>).</li>
<li>Phantom keypresses from split mouse sequences are suppressed.</li>
<li>Visual line mode highlights at once instead of on the next cursor move.</li>
</ul>
<p><strong>Colours and light themes</strong></p>
<ul>
<li>Unstyled cells use the terminal's real default foreground instead of white,
and SGR 39 and 49 reset to transparent instead of a fixed default. This fixes
light themes (<a href="https://github.com/Gaurav-Gosain/tuios/issues/41">#41</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/issues/72">#72</a>,
<a href="https://github.com/Gaurav-Gosain/tuios/issues/74">#74</a>).</li>
</ul>
<p><strong>Responsiveness</strong></p>
<ul>
<li>Closing a window with <code>exit</code> or <code>ctrl+d</code> no longer waits out a 500ms timeout
(now 10ms), and a race that lost the close notification about half the time
is gone.</li>
<li>Background windows no longer show stale content until you touch them.</li>
</ul>
<p><strong>Other</strong></p>
<ul>
<li>Tape scripts send CRLF on Windows, contributed by @dodorz.</li>
<li>Many smaller fixes to scrollback, tiling toggles and overlay positioning are
listed in the
<a href="https://github.com/Gaurav-Gosain/tuios/compare/v0.6.0...v0.7.0">full changelog</a>.</li>
</ul>
<h2>Known limitations</h2>
<ul>
<li>OSC 66 text sizing breaks with scrollback and when a window moves.</li>
<li>Sixel passthrough exists but is disabled until pixel-level clipping is
implemented, so sixel images cannot be cropped to a window. Use kitty
graphics.</li>
<li>The kitty animation protocol (<code>a=f</code>, <code>a=a</code>, <code>a=c</code>) was tried and dropped. It
needs image IDs to match between guest and host, and tuios remaps them. Run
programs that use it outside tuios for now.</li>
<li>Video without shared memory can flicker, depending on frame rate.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>v0.6.0</title>
      <link>https://tuios.dev/releases/v0-6-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-6-0</guid>
      <pubDate>Sun, 25 Jan 2026 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>Experimental Kitty graphics support, prefix-free window cycling in terminal mode, and a real terminal cursor with vi-mode shapes.</description>
      <content:encoded><![CDATA[<p>24 commits between v0.5.0 and v0.6.0, counting the v0.5.1 patch. Seven are
about one feature, kitty graphics: a program in a window can now show images
through the host terminal. It ships as experimental. The rest:</p>
<ul>
<li>Window cycling in terminal mode without the prefix key.</li>
<li>A real terminal cursor, so vi-mode cursor shapes work.</li>
<li>Compatibility fixes, several of them contributed.</li>
</ul>
<h2>Images, experimentally</h2>
<p>tuios redraws each window's content into its own grid, so an image cannot pass
through as is: its graphics commands carry positions that mean nothing to the
host terminal. tuios now translates them.</p>
<ul>
<li>The VT emulator reads the graphics commands, tuios tracks each placement
against its window, and forwards it to the host at the right cell.</li>
<li>A placement is moved when its window moves, resizes or scrolls, and hidden
when it is covered, dragged, or scrolled out of view.</li>
<li>Shared memory, file and direct transmission all work, with chunking for
large images.</li>
<li>Cell pixel sizes are reported to the PTY, so programs size images correctly.</li>
</ul>
<p><code>yazi</code> and <code>kitty icat</code> show real images in tuios windows on a host terminal
that supports them: Kitty, WezTerm, Ghostty, iTerm2, Foot or Contour.</p>
<p>Five fixes followed the feature in this cycle: clipping at window borders,
placements drifting against scrollback, image ID collisions between windows,
images left behind when a program leaves the alternate screen, and virtual
placements that assumed a placeholder grid tuios did not have. More edges were
found later.</p>
<h3>Known limits</h3>
<ul>
<li><code>TUIOS_KITTY_GRAPHICS=0</code> turns graphics off.</li>
<li>Images wider than the viewport are hidden rather than clipped.</li>
<li>Sixel is parsed but disabled until raster clipping exists.</li>
</ul>
<h2>Graphics detection by asking</h2>
<p>tuios used to guess graphics support from the terminal's name. Now it asks.</p>
<ul>
<li>A DA1 query detects sixel, and the kitty graphics query detects the kitty
protocol.</li>
<li>Reads poll with a timeout, so a terminal that never answers cannot hang
startup.</li>
<li><code>TUIOS_DEBUG_CAPS=1</code> logs what detection found. <code>TUIOS_KITTY_GRAPHICS</code> and
<code>TUIOS_SIXEL_GRAPHICS</code> override it either way.</li>
</ul>
<h2>Cycling without the prefix</h2>
<p>Window management used to be three keys away in terminal mode. Now it is one:</p>
<ul>
<li>macOS: <code>Opt+Tab</code> and <code>Opt+Shift+Tab</code> cycle windows.</li>
<li>Linux and Windows: <code>Alt+N</code> and <code>Alt+P</code>, because <code>Alt+Tab</code> belongs to the OS
window switcher.</li>
<li><code>Opt+Esc</code> or <code>Alt+Esc</code> leaves terminal mode.</li>
</ul>
<p>The bindings live in a new <code>[keybindings.terminal_mode]</code> section and show in
the help menu. This part of the release was contributed.</p>
<h2>A real cursor</h2>
<p>tuios used to paint its own cursor, a cyan block drawn into the grid. It now
moves and styles the real terminal cursor, so cursor shape sequences from
programs pass through. A shell in vi mode shows a block in normal mode and a
bar in insert mode, blinking included.</p>
<h2>Fixed</h2>
<ul>
<li>Paste works in daemon mode. Pasted text was written into the internal pipe
whose responses are discarded, so it vanished.</li>
<li>Arrow keys work in cmus and other ncurses programs. Programs that turn on
application cursor keys mode now get SS3 sequences instead of CSI.</li>
<li>Fast scrollback no longer crashes in colour comparison. Claude Code's output
was fast enough to trigger it. Contributed.</li>
<li>tuios builds on FreeBSD and OpenBSD.</li>
<li>macOS terminal handling is split from Linux, because the shared ioctl
constants were Linux-only.</li>
<li><code>--hide-clock</code> and <code>--window-title-position</code> survive opening new windows
instead of being overwritten by the config loader. These two shipped as
v0.5.1.</li>
<li>Animation bookkeeping is skipped when nothing is animating.</li>
</ul>
<p>Graphics stayed experimental well past this release, with horizontal clipping
and sixel still open. <code>TUIOS_KITTY_GRAPHICS=0</code> restores the old behaviour.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.5.0</title>
      <link>https://tuios.dev/releases/v0-5-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-5-0</guid>
      <pubDate>Thu, 25 Dec 2025 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>Persistent sessions backed by a daemon, multi-client attach over SSH, a remote control CLI, and BSP tiling with manual splits.</description>
      <content:encoded><![CDATA[<p>30 commits between v0.4.0 and v0.5.0, released on 25 December 2025. tuios now
runs as a session you attach to:</p>
<ul>
<li>A daemon keeps sessions alive when the client disconnects.</li>
<li>More than one client can attach to one session.</li>
<li>New CLI commands drive a running session from outside.</li>
<li>BSP tiling, with manual splits.</li>
</ul>
<p>Underneath, the code moved to the charm.land packages for Bubble Tea v2.</p>
<h2>Breaking changes</h2>
<ul>
<li><strong>Import paths.</strong> If you build on tuios as a library, the Charm packages
moved from <code>github.com/charmbracelet</code> to <code>charm.land</code>.</li>
<li><strong>Session state.</strong> State from before v0.5.0 does not carry over to the new
daemon format.</li>
<li><strong>CLI.</strong> <code>tuios new</code> and <code>tuios attach</code> take the session name as a
positional argument. The flags that did the same are gone.</li>
</ul>
<h2>Sessions that survive a disconnect</h2>
<pre><code class="language-bash">tuios new work      # create a session backed by a daemon
tuios ls            # list sessions
tuios attach work   # attach again
</code></pre>
<p>Detach, close the terminal, or lose the SSH connection, and the session keeps
running. Attaching again brings back windows, layouts, BSP trees, screen
contents and scrollback. A session lasts as long as the daemon process. The
daemon is started in-process.</p>
<p>This works on Windows too. The daemon uses Unix sockets and ConPTY, which
Windows has had since Windows 10 build 17063.</p>
<p>In daemon mode there are two VT emulators, the daemon's and the client's, and
both answered terminal queries. The extra answers printed as text, such as
<code>^[[?62;1;6;9;15;18;22c</code> on reattach. The first fix dropped every reply, which
made fish wait two seconds at startup for a Device Attributes reply that never
came. What shipped: the daemon's emulator answers queries, and the client's
drops its copies, so programs get their replies and nothing prints twice.</p>
<p><em><a href="https://tuios.dev/releases/v0-5-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<h2>More than one client</h2>
<ul>
<li>Several clients can attach to one session and see the same thing. Focus,
mode changes, workspace switches and window lifecycle sync in real time.</li>
<li>The session renders at the smallest attached client's size, so nobody gets a
cropped frame.</li>
<li>The SSH server maps the username to a session, so <code>ssh -p 2222 work@host</code>
attaches to <code>work</code>. Connecting without a name shows a session picker.</li>
</ul>
<p>A typical use is pair debugging: one person creates the session and the other
attaches from another machine.</p>
<p>Most of the fixes in this release made this stable. Client teardown, daemon
goroutines and window callbacks had races that only show with two clients on
one state. They got <code>sync.Once</code> on close, WaitGroup tracking, an atomic flag, a
five-second shutdown timeout, and tests under the race detector.</p>
<h2>A CLI for a running session</h2>
<ul>
<li><code>tuios send-keys</code> sends keys to tuios for window management, or with
<code>--literal --raw</code> straight to the focused PTY, one character at a time.</li>
<li><code>tuios run-command</code> runs any tape command by name.</li>
<li><code>tuios set-config</code> changes configuration at runtime.</li>
<li><code>tuios tape exec</code> runs a tape file against the session.</li>
<li><code>tuios list-windows</code>, <code>tuios get-window</code> and <code>tuios session-info</code> read daemon
state with no TUI attached, with <code>--json</code> for scripts.</li>
<li><code>tuios logs</code> tails the daemon.</li>
</ul>
<p>All of them have shell completion.</p>
<h2>BSP tiling</h2>
<p>A binary space partitioning layout. New windows follow a spiral, alternating
vertical and horizontal splits. When the spiral guesses wrong:</p>
<ul>
<li><code>Ctrl+B -</code> and <code>Ctrl+B |</code> split explicitly.</li>
<li><code>Ctrl+B R</code> rotates the split at the focused window.</li>
<li>Preselection chooses where the next window lands, and the dock shows the
direction of the next split.</li>
<li>An equalize command resets every ratio to 50/50.</li>
</ul>
<p>Trees are kept per workspace and saved in daemon state, so a layout survives a
detach and reattach.</p>
<h2>Snapping, appearance and animations</h2>
<ul>
<li>Dragging a window to a screen edge snaps it: top centre for fullscreen, the
left or right edge for a half, corners for quarters. A window has a minimum
size, so it cannot be dragged into nothing.</li>
<li><code>window_title_position</code> puts titles at the bottom, the top, or nowhere.</li>
<li><code>hide_clock</code> removes the clock overlay.</li>
<li>Titles show the window's custom name or the terminal's own title instead of
a default ID.</li>
<li>Animations can be turned off with <code>--no-animations</code> or with a keybind. Off
means off: snap, minimize and restore apply at once instead of playing a
zero-length tween that flashes.</li>
<li>Recorded tapes start with <code>DisableAnimations</code>, so playback looks the same on
any machine.</li>
</ul>
<h2>tuios as a library</h2>
<p>A first cut: <code>pkg/tuios</code> exposes the app as a Go package, with functional
options for theme, shell and animations, and the recommended <code>tea.Program</code>
settings for embedding it.</p>
<h2>Under the hood</h2>
<ul>
<li>The module moved to charm.land: Bubble Tea v2.0.0-rc.2, Lipgloss v2, Wish v2,
and sip v0.1.11 to match.</li>
<li>The CLI was split into one module per command.</li>
<li>The VT emulator synced with upstream: about forty deprecated mode constants
renamed, a nil colour panic fix ported, and grapheme width calculation
simplified enough to drop two dependencies.</li>
<li>The layout, pool and theme packages got tests, and staticcheck and go vet run
clean.</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Swapping windows in tiling mode updates the BSP tree, so a swap no longer
snaps back on the next layout pass.</li>
<li>Shift+Tab reaches the PTY as backtab even when the terminal reports extra
modifier bits.</li>
<li>On macOS, some <code>opt+</code> bindings were registered as <code>alt+</code>.</li>
<li>Reattaching to a tiled daemon session sized windows from the stale 80x24
handshake. Tiling now waits for the real size.</li>
<li>Remote commands send maps and slices correctly, and the inspection commands
work with no TUI attached.</li>
<li>tuios-web got a <code>--no-animations</code> flag, theme setup, and a curl install
script. An AUR conflict between <code>tuios</code> and <code>tuios-bin</code> was fixed.</li>
</ul>
<h2>Documentation</h2>
<p>Five new guides: BSP tiling, tape recording, the ShowKeys overlay, multi-client
sessions, and the library API.</p>
<p>A correction: the GitHub notes for v0.5.0 list tape recording and ShowKeys as
new features. Both shipped in v0.4.0. This release added their documentation.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.4.0</title>
      <link>https://tuios.dev/releases/v0-4-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-4-0</guid>
      <pubDate>Wed, 03 Dec 2025 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>The web terminal moves out into the sip library, tape scripting gets a recorder and a manager UI, and a ShowKeys overlay draws your keypresses for recordings.</description>
      <content:encoded><![CDATA[<p>51 commits between v0.3.0 and v0.4.0, with four patch releases along the way.
Three things are new:</p>
<ul>
<li>A web terminal, as the separate <code>tuios-web</code> binary built on the
<a href="https://github.com/Gaurav-Gosain/sip">sip</a> library.</li>
<li>Tape scripting, with a recorder and a manager UI.</li>
<li>ShowKeys, an overlay that draws your keypresses for screen recordings.</li>
</ul>
<p>The patch releases fixed resizing in floating mode and made the quit dialog ask
only when something is running.</p>
<h2>The web terminal</h2>
<p><code>tuios-web</code> serves tuios in a browser. It is a separate binary, so the main
<code>tuios</code> binary carries no server code, and people who never use a browser
never install one. It is a thin wrapper that hands tuios instances to sip's
Handler interface. sip serves any Bubble Tea app in a browser.</p>
<p>It went through three designs before the release. It started as a <code>tuios web</code>
subcommand: WebTransport with a WebSocket fallback, xterm.js with WebGL on the
client, and a bundled Nerd Font. That embedded about 10MB of web assets in the
repository and put an HTTP server in the window manager. The command then
became its own binary, and the server moved into sip, taking the 10MB with it.</p>
<p><code>tuios web</code> was added and removed within this cycle, so no tagged release ever
shipped it and there is nothing to migrate.</p>
<p>The rebuilds fixed two defects:</p>
<ul>
<li>Web sessions used to start the tuios binary as a subprocess. They now run
tuios in-process over pipes, like the SSH server.</li>
<li>The first frame was drawn at a fixed 80x24 before the browser reported its
size, which left artifacts. The session is now created after the browser's
first resize, so the first frame has the right size.</li>
</ul>
<h2>Tape scripting</h2>
<p>A <code>.tape</code> script drives tuios from a file: open terminals, type into them,
manage windows, switch workspaces and modes, and pause between steps.</p>
<ul>
<li><code>tuios tape validate</code> checks a script.</li>
<li><code>tuios tape play</code> runs it live with a progress indicator.</li>
<li>Playback goes through the same Bubble Tea update loop as live input, so a
tape and a person at the keyboard run the same code.</li>
<li>The recorder captures your starting state, window actions, mode switches and
workspace switches. Consecutive characters become one <code>Type</code> command, so a
recorded tape reads like one written by hand.</li>
<li>The tape manager on <code>Ctrl+B T m</code> browses, records and manages tapes without
leaving the session.</li>
</ul>
<p>A headless <code>tape run</code> mode existed during development. It never worked
properly and was removed rather than shipped.</p>
<h2>ShowKeys</h2>
<p>tuios can draw your keypresses in the bottom right as you type, inspired by
nvzone/showkeys. Turn it on with <code>--show-keys</code> or toggle it with <code>Ctrl+B D k</code>.</p>
<ul>
<li>Keys are drawn as pills styled like the window title, with modifiers spelled
out.</li>
<li>Repeats collapse into a count (<code>j ×3</code>).</li>
<li>Keys stay for three seconds. The first version used one, which was too short
to read.</li>
</ul>
<p>The leader key is now configurable as well. It was fixed at <code>Ctrl+B</code>, and now
comes from <code>leader_key</code> in the <code>[keybindings]</code> section. The help menu and
every chord follow it, and ShowKeys highlights it so a viewer can spot it in a
recording.</p>
<p><em><a href="https://tuios.dev/releases/v0-4-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<h2>Changed: the patch releases</h2>
<p>v0.3.1 to v0.3.4 shipped in the first week of November. Most of it fixed
resizing in floating mode.</p>
<ul>
<li>During a drag, the window geometry updates at once and the PTY resize waits
until release, so the shell no longer gets a stream of resize signals.</li>
<li>The emulator's size stays in sync with the window's, so content no longer
sticks at the old size while the border moves.</li>
<li>A "Resizing... WxH" indicator shows in the window during a drag. In tiling
mode, neighbours pulled along by the drag show it too.</li>
<li>After a drag, PTY buffers are flushed and polling waits for the shell to
redraw its prompt at the new width, which fixed half-drawn prompts.</li>
<li>If the cursor ends up below the view after a height reduction, the view
scrolls to keep the prompt visible.</li>
<li>Dragging right after a resize no longer freezes the window.</li>
</ul>
<p>Other changes in the patches:</p>
<ul>
<li>Quitting with open terminals shows a confirmation. It asks only when a
terminal's foreground process is running something, so quitting idle shells
just quits.</li>
<li>The welcome screen shows on any workspace with no visible windows, not only
when the whole session is empty.</li>
<li>The shell is configurable. This mattered most on Windows, where tuios always
started PowerShell.</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Decimal durations in tapes parse correctly, so <code>1.5s</code> no longer rounds.</li>
<li>The render cache is cleared when leaving resize mode, so the resize
indicator disappears at once.</li>
<li>ShowKeys compares modifiers, so <code>Ctrl+L</code> followed by <code>L</code> shows two keys
instead of one pill.</li>
</ul>
<h2>Project</h2>
<ul>
<li>A contributing guide.</li>
<li>Package doc comments across all internal packages, a golangci-lint cleanup,
and a modernization pass (<code>any</code> over <code>interface{}</code>, <code>slices.Delete</code>, built-in
<code>min</code> and <code>max</code>).</li>
<li>README keybindings use kbd tags.</li>
<li><code>tuios.exe</code> is gitignored.</li>
</ul>
<p>The <code>.tape</code> format introduced here is the one project tapes were later built
on.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.3.0</title>
      <link>https://tuios.dev/releases/v0-3-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-3-0</guid>
      <pubDate>Wed, 05 Nov 2025 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>Bubble Tea v2 with keyboard enhancements, configurable tiling layouts, theming turned opt-in, and a scrollback rewrite.</description>
      <content:encoded><![CDATA[<p>27 commits in the three days after v0.2.0, including the v0.2.1 and v0.2.2
patch releases. The main change is the move to Bubble Tea v2, which lets tuios
use the kitty keyboard protocol. Tiling also got real layout controls, themes
became opt-in, and scrollback got 10 to 20 times faster.</p>
<h2>Breaking changes</h2>
<ul>
<li><strong>Themes are off by default.</strong> v0.2.0 turned them on, and an opaque themed
background fights any program that wants to set its own. The terminal
background is now transparent and the default theme is none, so you get your
terminal's own colours. To get the v0.2.0 look back, add
<code>theme = "tokyonight"</code> (or any theme) to your config.</li>
</ul>
<h2>Keys that mean what you typed</h2>
<p>tuios moved to Bubble Tea v2.0.0-rc.1 and handles its keyboard enhancement
messages. On a terminal that supports the kitty keyboard protocol, tuios
detects it and turns it on, with nothing to configure.</p>
<p>A classic terminal cannot tell Shift+Enter from Enter, and cannot report
Super+Space at all. With the protocol on, these arrive as separate keys,
complex modifier combinations work, international layouts report correctly,
and the keys reach the program in the pane unchanged.</p>
<p>In terminal mode, tuios used to catch the tiling resize keys, so you could not
type <code>&#x3C;</code>, <code>></code>, <code>{</code> or <code>}</code> into a shell. Now only the <code>Ctrl+B</code> prefix is caught
in terminal mode, and every other key goes to the PTY.</p>
<h2>Tiling you can shape</h2>
<ul>
<li>The master window ratio is configurable from 30% to 70%.</li>
<li>Eight new resize operations, with directional variants.</li>
<li>Each workspace remembers its layout and restores it.</li>
</ul>
<h2>Appearance</h2>
<p>These live in a new <code>[appearance]</code> config section, with matching flags.</p>
<ul>
<li>The dock can sit at the bottom, at the top, or be hidden. Contributed by
Cjreek.</li>
<li>Nine border styles: rounded, normal, thick, double, hidden, block, ascii, and
two half-block variants.</li>
<li>The window control buttons can be hidden.</li>
<li>Windows follow the cursor visibility a program asks for, so cmatrix hides the
cursor and nvim shows it.</li>
</ul>
<h2>Scrollback</h2>
<p>Scrollback moved from a growing slice to a fixed-size ring buffer. The common
operations went from O(n) to O(1), which is 10 to 20 times faster once the
buffer is full. The size is configurable from 100 to 1,000,000 lines, with a
default of 10,000.</p>
<h2>Fixed</h2>
<ul>
<li>Switching workspace during an animation left windows where the animation had
reached, sometimes one fullscreen with the rest piled on top. Animations now
finish on a switch: the old workspace snaps to its tiled layout at once, and
the new one tiles with its usual animation.</li>
<li>Grid layouts with five or more windows no longer leave dead space at the
bottom.</li>
<li>With the dock at the top, mouse resizing no longer uses boundaries two lines
off.</li>
<li>The parent <code>TERM</code> variable is kept, with <code>xterm-256color</code> as a fallback.</li>
<li>tuios answers XTWINOPS queries (CSI 14, 16 and 18 t), so programs that ask
for the window size in pixels or cells get an answer.</li>
<li>PTY setup is split into platform-specific files, which fixes the Windows
build after Unix-only process attributes broke it.</li>
<li>Viewport clipping mis-parsed ANSI escapes because of a logical AND that
should have been OR.</li>
</ul>
<h2>Project</h2>
<ul>
<li>Contributor plumbing, mostly from cr2007: issue forms for bugs and feature
requests, an auto-labeler, a PR template, a security policy, and README
keybindings shown with kbd tags.</li>
<li>The README notes kitty protocol support, from ShalokShalom.</li>
</ul>
<p>v0.3.0 was tagged on 5 November 2025. Everything after it builds on the Bubble
Tea v2 migration.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.2.0</title>
      <link>https://tuios.dev/releases/v0-2-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-2-0</guid>
      <pubDate>Sun, 02 Nov 2025 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>340 color themes that restyle the UI and the terminal palette together, a new PTY layer, and windows that can no longer leave the screen.</description>
      <content:encoded><![CDATA[<p>Eight commits. Two are large: tuios got themes, and a new PTY layer under every
window. This is also the release where tuios restores your terminal properly
when it exits.</p>
<h2>Themes</h2>
<p>tuios ships over 340 colour themes from bubbletint. Pick one with <code>--theme</code>
(the default is <code>tokyonight</code>).</p>
<ul>
<li>A theme recolours the programs in your windows too, not only the chrome. A
custom SGR handler maps the 16 ANSI colours to the theme's palette, so <code>ls</code>,
vim and htop follow it.</li>
<li>256-colour and RGB sequences pass through unchanged, so a program that asks
for an exact colour still gets it.</li>
<li>Borders show state: an unfocused window uses the theme's red, a focused
window in window mode is bright cyan, and in terminal mode it is bright
green.</li>
<li><code>--list-themes</code> prints every theme, and <code>--preview-theme</code> shows a theme's 16
ANSI colours with their hex values.</li>
</ul>
<h2>A new PTY layer</h2>
<p>Every window runs on a pseudo-terminal, and this release swaps the library
that provides it: go-pty out, charmbracelet's xpty in, for a cleaner API and
better Windows ConPTY support.</p>
<p>The switch first broke shell startup. Processes no longer got the PTY as their
controlling terminal, which shells such as fish need, so windows opened and
died at once with exit status 1. The fix, in the same release, sets up the
process session and controlling terminal explicitly, as the old library did
implicitly.</p>
<h2>Changed and fixed</h2>
<ul>
<li>Windows can no longer be dragged or resized off screen. They stay inside the
viewport and out of the dock, which also fixes drawing artifacts at the
edges.</li>
<li>tuios exits cleanly. It handles SIGINT and SIGTERM, and on the way out it
turns off mouse tracking, restores the cursor, and leaves the alternate
screen, so your shell prompt is intact.</li>
<li>The README gave two background refresh rates. It now says 30Hz, not 20Hz.
Caught by ShalokShalom.</li>
<li>The Nix packaging workflow now runs on tag pushes, not only on release
events, so it runs for every version.</li>
</ul>
<p>v0.2.0 was tagged on 2 November 2025. Two patch releases followed within days.
Their changes are on the <a href="https://tuios.dev/releases/v0-3-0">v0.3.0 page</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>v0.1.0</title>
      <link>https://tuios.dev/releases/v0-1-0</link>
      <guid isPermaLink="false">https://tuios.gaurav.zip/releases/v0-1-0</guid>
      <pubDate>Fri, 31 Oct 2025 00:00:00 GMT</pubDate>
      <dc:creator>Gaurav Gosain</dc:creator>
      <description>The first tagged release. A floating and tiling terminal window manager with a vim-style copy mode, scrollback, a TOML config with rebindable keys, and packaging for most platforms.</description>
      <content:encoded><![CDATA[<p>The first release with a minor version number. The first commit, on 6
September 2025, was already a working prototype: floating windows, tiling,
workspaces, an SSH server and window animations, all in one flat Go package.
The 70 commits after it went through 26 v0.0.x tags in under two months and
added what you need to install tuios, configure it, and copy text out of it.</p>
<h2>Breaking changes</h2>
<ul>
<li>The CLI moved from flat flags to subcommands. <code>--ssh</code> became <code>tuios ssh</code>,
and the other flags moved the same way.</li>
</ul>
<h2>Scrollback and copy mode</h2>
<p>Before this release, text that scrolled off screen was gone, and text on
screen could not be copied. Both are fixed.</p>
<ul>
<li><strong>Scrollback.</strong> Each window keeps 10,000 lines. Enter it with <code>Ctrl+B [</code> or
by scrolling the mouse wheel up, and move with the arrows or vim keys. The
upstream VT library had no scrollback, so tuios runs on a fork, and the
change was sent upstream as a pull request to charmbracelet/x.</li>
<li><strong>Copy mode.</strong> Vim-style motions: <code>hjkl</code>, word motions, <code>gg</code> and <code>G</code>, count
prefixes (<code>10j</code>, <code>100G</code>), <code>f</code>, <code>F</code>, <code>t</code> and <code>T</code> character search that handles
wide characters, <code>/</code> and <code>?</code> search with highlighted matches, <code>%</code> for bracket
matching, and <code>v</code> or <code>V</code> visual selection yanked to the clipboard with <code>y</code>.</li>
<li><strong>Mouse selection.</strong> Click and drag, double-click for a word, triple-click
for a line.</li>
</ul>
<p>Copy mode started as one 2,137-line file and was split into six modules before
the tag.</p>
<h2>Configuration and the CLI</h2>
<ul>
<li><strong>A config file.</strong> <code>~/.config/tuios/config.toml</code> is created on first run with
comments that document it, and follows XDG. Every keybinding in every mode
can be rebound.</li>
<li><strong>Actions, not code.</strong> A key maps to an action name and an action name maps
to a handler, so rebinding needs no code change. The help overlay is built
from the config, so it shows the keys you actually have.</li>
<li><strong>Platform defaults.</strong> macOS gets <code>opt</code> where Linux gets <code>alt</code>.</li>
<li><strong>Subcommands.</strong> The CLI moved to Cobra, with Fang for help output: <code>tuios</code>
runs it, <code>tuios ssh</code> runs the SSH server, and <code>tuios config</code> and
<code>tuios keybinds</code> manage the two above. Shell completions and man pages are
generated.</li>
</ul>
<h2>The prefix key</h2>
<p>Everything hangs off a tmux-style <code>Ctrl+B</code> prefix, which now has submenus:</p>
<ul>
<li><code>w</code>: workspaces (switch to one, or move a window to one)</li>
<li><code>m</code>: minimize and restore</li>
<li><code>t</code>: window commands</li>
<li><code>[</code>: scrollback</li>
<li><code>q</code>: quit</li>
</ul>
<p>A which-key overlay appears after half a second and shows what each submenu
offers.</p>
<p>On macOS, Option plus a number types a character such as <code>¡</code> or <code>™</code> instead of
sending a modifier. tuios recognises those characters as workspace switches,
and the help text says "Opt" on a Mac and "Alt" elsewhere.</p>
<h2>Rendering is 30 times faster</h2>
<p>The prototype rendered every cell of every window through a new lipgloss
style on every frame. A 13.45-second CPU profile spent 4.85 seconds in
<code>renderTerminal</code>. Two changes fixed it:</p>
<ul>
<li>A style cache keyed on cell attributes. A hit costs about 99 nanoseconds and
no allocations.</li>
<li>Terminal content is written as ANSI escape codes directly, skipping a style
pipeline built for UI boxes. Neighbouring cells with the same style are
batched, which cut style renders per frame from about 2,000 to about 50.</li>
</ul>
<p>After both, <code>renderTerminal</code> took 0.16 seconds in the same profile, and total
CPU use fell from 53% to 24%. The input path also stopped clearing the render
cache on every keystroke.</p>
<p><em><a href="https://tuios.dev/releases/v0-1-0">An interactive figure goes here. Open the page to use it.</a></em></p>
<h2>Terminal behaviour</h2>
<ul>
<li>Mouse events reach programs on the alternate screen, so drag-to-select works
in vim, scrolling in less, and clicking in htop.</li>
<li>Paste works through OSC 52 and bracketed paste, including <code>Cmd+V</code>.</li>
<li>The alternate screen is detected through VT callbacks instead of guessed.</li>
<li>nushell no longer clears its own output. The VT library answered cursor
position queries with stale coordinates, so tuios now corrects those
replies.</li>
<li>The PTY layer changed twice and ended on charmbracelet/x/xpty, for Windows
ConPTY support. The forked VT package is vendored, so plain <code>go install</code>
works.</li>
<li>In tiling mode, swapping, minimizing and retiling only touch windows in the
current workspace.</li>
</ul>
<h2>Installing</h2>
<ul>
<li>GoReleaser builds for Linux, macOS, Windows, FreeBSD and OpenBSD.</li>
<li>Releases publish to a Homebrew tap and the AUR (<code>tuios-bin</code>), and there is a
one-line curl installer.</li>
<li>The Nix package and devshell were the project's first outside contribution.</li>
<li>The binary is statically linked, so there is no glibc version to match.</li>
<li><code>--ascii-only</code> draws without Nerd Font icons, for machines that do not have
one. It was added four days before the tag.</li>
</ul>
<h2>Fixed</h2>
<ul>
<li>Notifications stayed up for about 17 days instead of 1.5 seconds. A duration
already in milliseconds was multiplied by <code>time.Millisecond</code>.</li>
<li>Comparing cell colours could panic on a nil pointer: a non-nil <code>color.Color</code>
interface can hold a nil value. This was the last fix before the tag.</li>
<li>Typing over SSH did nothing after the restructure, because the input handler
was registered for local mode only.</li>
<li>On macOS, <code>exit</code> did not close the window when the exit message was missed.
The tick loop now checks the process directly.</li>
<li>Visual selection highlighted the empty cells past the end of each line. It
now stops at the text.</li>
<li>Mouse selection in copy mode was off by one row.</li>
<li>Dragging a window a few pixels no longer corrupts the tiled layout.</li>
<li>The Windows build compiles again, after resize signalling was split into
platform-specific files. Nobody had reported running it there.</li>
</ul>]]></content:encoded>
    </item>
  </channel>
</rss>
