Skip to content

Sendoff v0.3.0 — Doctor, images by path, hardened preview

Latest

Choose a tag to compare

@exviolet exviolet released this 04 Sep 14:06
· 10 commits to master since this release

Three weeks of work: a first run that explains itself, images that reach the agent as
paths, workspace editing where you switch workspaces, and a markdown preview that is no
longer a route from a file you opened to your shell.

Upgrading from v0.2.0 is a drop-in replacement. Same app identifier, same data
directory, same database version — download the new AppImage and run it. Nothing moves,
nothing migrates, and rolling back to v0.2.0 works.

The first run now shows what Sendoff sees

Downloading Sendoff used to open an empty editor with "Untitled" and a placeholder — no
hint of what the thing is for. First launch now walks exactly one chain: see a target,
bind it, write, Ctrl+Enter, see the confirmation. No theme picker, no font picker, no
tour. Continue without a target and Escape are available at every step, because
without a target Sendoff is still a working editor and a mandatory wizard would be lying
about that.

It also stops at the honest boundary: Sendoff confirms that its send path ran, never
that the agent read anything. It cannot know the second one.

Sendoff Doctor

The empty picker was previously a dead end — no targets, no reason given. Two real
incidents were impossible to investigate after the fact: a send-path validator rejecting
a live handle, and IndexedDB becoming unreadable after a WebKit version change.

Doctor reports, per target, whether the executable is visible in Sendoff's own PATH
(a GUI launch does not inherit your shell's), whether discovery actually ran, and the live
handle the target hands back — the exact shape a send is validated against. Plus the
versions that decide whether your data is readable at all: Sendoff, Tauri, WebKitGTK, and
the data directory.

It only reports. It fixes nothing, configures nothing, and sends nothing to a live agent.
Ctrl+Shift+PSendoff Doctor, or from the first-run screen.

Images reach the agent as paths

Paste a screenshot with Ctrl+V, drop an image file into the editor, or pick one from the
palette — Sendoff inserts its absolute path into the prompt. Coding agents read images from
a path, so this is what actually arrives: the terminal carries text, not pixels.

Verified on both Codex and Claude Code with an image containing a random six-digit number
that does not appear in the filename. Both read it back correctly, so the channel works and
does not depend on which agent the tab is bound to.

A pasted image is written into Sendoff's own data directory; a file you dropped or picked is
referenced where it already lies and never copied.

Workspaces are editable where you switch them

F2 in the workspace switcher (Ctrl+Shift+W) opens rename and delete in place. Deleting a
workspace moves its tabs to the next one instead of discarding them, and says so before you
commit.

Security: the markdown preview is no longer a route to your shell

An internal review found a chain in v0.1.x and v0.2.0: a markdown file you did not write —
opened and previewed — could run JavaScript in the webview, and from there reach the shell
plugin. It required opening an untrusted .md and turning preview on; it was found in
review, not reported in the wild.

Three independent layers now close it:

  • Rendered markdown is sanitised before it reaches the DOM.
  • A strict Content-Security-Policy: scripts load from the app only, with no inline
    execution.
  • The tmux permission is scoped to four named subcommands with argument validators,
    instead of allowing arbitrary arguments. send-keys accepts the literal Enter and
    nothing else, so it submits and cannot type.

The last one is the layer that mattered: with arbitrary arguments allowed, injected
JavaScript could run commands in any pane. The security boundary in the README describes
the new model.

Also in this release

  • Global shortcuts no longer leak through open dialogs. Ctrl+W used to close the tab
    underneath a picker; a second picker could be stacked on the first.
  • When a session write fails, the reason is shown instead of being swallowed silently.
  • Cleaning up empty tabs no longer leaves an empty group chip behind, or a selection
    pointing at tabs that are gone.
  • The frontend, which lived in a separate sendoff-web repository behind a submodule, is
    now part of this repository with its full history. Source builds and ./update.sh no
    longer touch submodules.

Download

Sendoff_0.3.0_amd64.AppImage — x86_64 Linux.

sha256  6f8db75ff1bb9ca9306b2340f38457a6d3101f5807990fc2c08fe22877332a6b

Needs glibc ≥ 2.35 — Ubuntu 22.04+, Debian 12+, Fedora 36+, Arch. Built in an Ubuntu
22.04 container for that reason: an AppImage bundles its libraries but not glibc, so
building on a rolling distro would produce a file that only runs on rolling distros.

⚠️ Don't mix the AppImage and a source build on the same machine. The AppImage bundles
WebKitGTK 2.50, while current distributions ship 2.52+, which writes IndexedDB in a newer
metadata format and silently upgrades the database the first time it opens it. After that
the AppImage can no longer read it and shows an empty editor plus a storage error. Your
data is intact and is never overwritten — when Sendoff cannot read, it stops writing
altogether. Go back to the build you were using and your tabs are there.