Release ·
cowork-deck v0.3.0
A scenario used to leave nothing behind. sessions.json dropped the entry when
the tile closed, so a schedule that fired at 03:00 into a session nobody was
there to watch was unrecoverable by morning — the only surviving trace anywhere
was one row per scenario in schedule_state.json, written by the scheduler and
only for scheduled fires. This release gives scenario runs a journal and a
screen to read it on.
What people get
Scenario run history (#217, in three parts: #218, #219, #220). Every run is journalled — how it started, how long it took, and the final assistant message — and a History screen beside Terminals / Board / Pull requests lists them newest first, filterable by scenario and by trigger.
- The journal is
runs.jsonlin the app data dir, one appended line per event. Append-only, because a store that truncates before it writes cannot be trusted with a file written on every launch; versioned per line, because after an upgrade the file physically holds lines from several app versions and a header would lie about the ones below it. - Rows carry snapshots, not lookups: the name, icon, expanded prompt and parameter values as they were. Renaming a scenario, deleting it, or deleting its workspace cannot rewrite the past.
- A row that produced nothing says which nothing it was — still running, no
session started (with the scheduler’s reason), no transcript ever reported, or
the transcript is gone. Never an empty box: the run happening and the run
producing nothing are different facts. A conversation that was
/cleared since says so out loud rather than presenting a stranger’s tail as its result. - Three actions on a row, and deliberately no fourth. Go to the session
while it is still live, switching workspace first if it is running in another
one. Re-run, through the usual “Launch parameters” form with the recorded
values pre-filled and selected — never silent, because a scenario’s parameters
may name a branch, a target or a person — and reconciled against the scenario
as it stands now, so a placeholder the prompt has since lost is dropped and
one it has gained comes up empty. Reveal the transcript in the file
manager, reveal only, never
open: a.jsonlis not handed to whatever is registered for it. - Where an action cannot work the control says why, on itself and in its
accessible name — a scenario that was deleted, a workspace that was, a
transcript that was never written.
aria-disabledrather thandisabled, so the reason is reachable without a mouse. - History is immutable. No row can be edited or deleted; a journal whose rows can be revised answers nothing. Erasing exists at one granularity — a scenario’s history wholesale, from the head of the screen while it is narrowed to that scenario, so the rows it erases are the ones on screen.
- Recording can be switched off, and the screen says so rather than looking empty. Retention is the last 100 runs per scenario, pruned at app start — a time window would keep three records for a monthly job and two thousand for an hourly one.
- The scenario’s sidebar row grows a state dot for how its last run went, which opens the history narrowed to that scenario. An indicator and nothing else — that row has learned this lesson once already, when one ⏰ was both a status badge and a real launch, and reaching for information started a session.
Shift+Enter writes a second line (#234). It used to submit the
half-written message. xterm maps Enter to a bare CR whatever modifiers are
held, so Shift+Enter reached claude byte-identical to Enter and claude
did the only thing a bare CR allows. The app is the terminal here, so it now
makes the binding every real terminal makes — the one claude’s own
/terminal-setup writes into iTerm2 and VS Code: ESC + CR. Alt/Option+Enter
and Ctrl+Enter map to the same newline, since neither can mean anything else
and they are what a person tries next. Plain Enter still submits, and zoom
keeps its binding — Cmd+Enter on macOS, Ctrl+Shift+Enter on Windows and
Linux.
Two defects fixed
- The status pill took the keyboard every five seconds (#203) — and did it
precisely while a session sat waiting for an answer, which is the state the
pill exists to report. On macOS
show()ismakeKeyAndOrderFront:, and a focusable window duly became the key window on every poll tick. The pill is now built non-focusable, and the count is only emitted when it actually changes. Typing into a terminal is no longer interrupted. Open in browserdid nothing (#252) — no browser, no navigation, no feedback. A Tauri v2 webview has nowhere to open atarget="_blank"link, so the navigation was simply dropped. Five other links were dead the same way: the pull request row, the GitHub screen, links and images in rendered markdown, the diff drawer, and a card. All six now go through one gate that openshttp/httpsin the system browser and refuses everything else. The capability grants URL-opening scoped to those two schemes and nothing more — a URL out of a pull request description must never be able to name a file to run.
Housekeeping, no behaviour attached
- 44 spec and plan documents retired (#253) — the record of a workflow this
project no longer uses. Work is scoped in GitHub issues and decisions are
recorded in
docs/adr/; a standalone spec was a third, unmaintained account of intent. Four code comments that cited one for a measurement now state the measurement inline. - The first two ADRs (#216) — how connected social accounts will hold credentials, and who uses them over what. Both are inputs to #205; the “the app stores no tokens” invariant is narrowed rather than deleted.
- Where agents look things up (#202) — the issue tracker, the five canonical
triage labels, and the domain-doc layout, written down so a skill does not
guess and open a pull request against
main. - The README gains the Features bullet the history screen shipped without.
Known, and tracked
Found while building this, left out on purpose:
- #235 — the history screen reads an unreadable journal as an empty one.
- #236 — no test covers the history screen’s boot-level wiring.
- #249 — an unpinned scheduled scenario runs in whichever workspace happened to be active. The form says so; saying so is not the fix.
- #255 — every modifier+key pair other than the three now translated still collapses. The real answer is negotiating the kitty keyboard protocol.
Still open from v0.2.0: #199 (after /clear, restart and auto-restore
resume the pre-clear conversation), #195 (a non-UTF-8 transcript reports
zero tokens and no name, silently), #194 (a renamed card tile loses the ☑
that says which card it is on).
Install
macOS — download the .dmg for your architecture (aarch64 for
Apple Silicon, x64 for Intel), drag the app to Applications, then
clear the quarantine flag once:
xattr -cr /Applications/cowork-deck.app
Linux — download the .AppImage, chmod +x it and run, or
install the .deb.
The app checks this page for updates on launch and installs them
in place; the xattr step is first-install only.
Downloads for v0.3.0
- macOS · Apple silicon
- macOS · Intel
- Linux · AppImage
- Linux · Debian and Ubuntu
- Linux · Fedora and RHEL
On macOS, read the Gatekeeper note first.