cowork-deck

Release ·

cowork-deck v0.6.0

The largest release so far: 63 pull requests on dev — 35 of them work rather than dependency bumps — and every issue in the v0.6.0 milestone. Four things the deck could not do at all before: it remembers what past sessions worked out, it says how much of each connected AI is left, it says what a session actually ran, and it answers without its window being in front. Three epics closed to get there, and a fourth — project memory — went from staged-and-uncalled to working.

Sessions remember, and later ones read it

Project memory (#35) was in the bundle and uncalled in 0.5.0. It works now, end to end.

A closing session writes its own note — what it did, what was decided, what broke and why. It fills itself, so nothing depends on anybody remembering to write anything down. It is asked, and it costs you money: the transcript goes to a model on your own Claude account, and the question at the close says so before the button that agrees to it. Answer once for good under Session notes… in the palette — ask each time, always, never.

What keeps the bill small is not restraint on your part. The transcript is reduced to its prose before anything is sent: tool calls, their output, thinking and injected context are most of the bytes of a working session and none of its meaning. What survives is capped, a session with nothing in it never reaches a model at all, and the summary runs on the cheap model — shortening prose that is already in the request does not need the strong one. Each capture prints what it cost.

Notes are markdown on your disk, under the same directory as your workspaces:

<config dir>/{workspace}/Sessions/2026-09/07-the-thing-you-fixed.md
<config dir>/{workspace}/Facts.md          durable claims, appended and never rewritten
<config dir>/Diaries/{room}/2026-09.md     lessons, global rather than per project

Diary rooms are global on purpose: that is what lets a mistake made in one repository stop the same mistake in the next. The model picks the room from a sentence you write.

The rail grew a fourth page. Memory lists everything ever written down — a heading per project, the most recent project first, lessons last — and it does not change with the project you have open, because memory spans them. It is a directory listing rather than a search, so it works on a machine that has downloaded nothing. Choosing a note reads it where the deck was, and one control gives the deck back. The field at the top takes a sentence rather than a keyword: “why did the cross build pick the wrong architecture” finds the session that answered it. You can write into it by hand too — a note, a fact, a fact that has stopped being true, a lesson filed into a room you pick rather than one a model picks. The foot of the page keeps the record: which sessions were summarised, which failed and why, and what the calls came to.

Your sessions can search it, and are handed it with the question. A launched session gets a search_memory tool of its own and is told when to reach for it — before changing code in an area it has not seen, before settling a question somebody here has already settled. It reads; it never writes. And because a rule in the system prompt about every question in general loses to context about this one, a question long enough to be a question arrives with the closest few passages already attached. Short instructions, slash commands and pasted code pay for nothing. When the corpus has nothing on it, it says so plainly rather than offering passages that did not match.

Memory now knows when. Asked in Russian what the project did yesterday, a session went to git log and never touched memory; asked what was done on phase 4, it searched memory (#462). “What did we do yesterday” is a question whose selector is when, put to a retriever that could only select on what — its nearest neighbours are whatever notes happen to talk about doing things, from any month. A note’s date is derived from its path rather than stored beside the vectors, which ADR-0004 makes the only place it can live: nothing is added to the cache and no reindex is needed. Every hit carries its date, search takes a window, and the period is read out of your own words in both languages. The same report found MIN_CHARS = 24, calibrated on English under a comment claiming a sentence in any language this app expects is longer — «что мы делали по фазе 4» is twenty-three characters and was refused on the count alone. The character floor is gone; the word floor, which was always language-neutral, still refuses “fix this indent”.

Searching needs a 479 MB embedding model, downloaded once per machine and offered rather than fetched behind your back. One resident sidecar serves the whole deck, so a search is milliseconds rather than seconds; it is given back after a few minutes of not being used. Everything is on your disk and nothing about a search reaches a network.

One limit worth knowing: sessions on Claude Code get notes, and Copilot, opencode and Codex ones do not yet — the deck says so rather than quietly skipping them.

Limits: what each AI has left, and where that number came from

A dozen sessions draw on one budget, and when it runs out they stall together (#301). The top bar says Limits, and behind that word is a dial per AI: its own logo, the five-hour window drawn as a ring around it, and the reading in figures underneath. Point at the word and the row opens with a card — the five hours and the week in full, each with its reading, when it lifts, and where the number came from. Press a dial for the caveats.

What does not go behind the point is the part you need without asking: the word itself turns amber when anything is nearly spent and red when anything is spent, out of every window of every AI. The hue is how much is left — green to three quarters, amber to nine tenths, red past it — and it is said in words too, because a band carried by hue alone is a band a person who cannot see the hue does not get. The logo in the middle stays the brand’s own colour: identity in the middle, level around it.

The source of a number is part of the number, written beside it rather than hidden in a tooltip. The account’s own accounting — the figure /usage draws, obtained by asking claude the way this app asks gh about GitHub — prints plain, because an unqualified number is the account’s. What the app saw from the sessions it runs says “this app only” after the number, and gets no ring at all: the app knows what it spent, not what was allowed, and it will not divide by a ceiling it invented. Where there is nothing, the card says “no reading” and the figure is a dash rather than a number it would have to invent.

The reading that matters most needs no percentage. When a session is refused, the app reads the limit banner on its way to the screen and says nothing moves until 19:00 — on screen, and in a notification while you are looking at something else. That survives a restart, and you are told again when it lifts.

Codex and Gemini sit beside Claude as coming soon: this deck does not read their limits yet, and a lineup that is stable across the day one of them starts working is worth more than one that shows only today. The reasoning is in ADR-0009.

Activity: which tools a session ran

A tile’s ctx 83.7k badge says what a session costs. The chart button next to it — and a click on the badge itself — now says what it did (#323): a count per tool, and three ways to read it.

  • By tool, the name the CLI itself used, with a bar scaled to the busiest row. Bash 334 and nothing else is a different session from twenty tools over a hundred calls, and the shape is visible before the digits are read.
  • By agent — the main conversation, then a row per subagent reading agent type — description, indented by how deep it was delegated. This is the section the terminal cannot give you: a session whose work was mostly delegated looks idle in its own scrollback.
  • By MCP server, shown only when there were MCP calls. Half the distinct tool names in a measured project were MCP across just two servers.

Failures and refusals are counted separately and shown only when there are any — a refused call never ran, and a session that declined three commands is not a session that broke three times.

The numbers come from the agent’s own log, not from anything the deck records (ADR-0008), and both consequences are the point rather than a limitation: they cover the whole conversation, including the part from before this window was open, and they are only as fresh as the log. The panel reads it while it is open and not otherwise. Claude Code, the Copilot CLI and opencode can all be read — a CLI with no reader says so rather than showing zeroes.

The deck, answerable without its window

Two surfaces, answering different questions on purpose (#393).

The status area — the menu bar on macOS, the notification area on Windows — answers on demand. Click the icon and a small panel drops under it, drawn with the deck’s own components: every AI’s meter, and the deck’s sessions ordered by what wants a person. A limit row opens that provider’s detail; a session row raises the window it lives in, even if that is a workspace window on another monitor. It carries no count, because that is the dock’s number.

The dock, or the taskbar, carries the number of sessions waiting. It is the glance, and it clears the moment you look at the deck — a badge you have learned to ignore is worse than none.

The icon follows the platform: a template image on macOS, so the system tints it against the menu bar the way every other icon up there behaves; the app’s icon in colour on Windows and Linux, where nothing tints. On Linux it carries a native menu with the same sections instead of the panel, because an indicator’s click is not deliverable to the application on most desktops and a panel opened on a click would never open. Both are built from one list. The decision is in ADR-0013.

The floating pill is gone (#394). It was the previous answer to the same question, and two answers is one too many.

Also in this release

  • A workspace’s colour runs down its whole group as a top-to-bottom gradient, strongest at the workspace row and fading through its sessions (#511). In a tree of a dozen sessions across four projects the eye finds “the green one’s sessions” without reading a name — the colour was an 8px dot before.
  • The terminal drawer takes the deck’s place from a control that gives it back (#346), and it is a rounded island like everything else rather than a square-cornered strip (#449).
  • One resize grip, five surfaces (#424): one gesture had three implementations and two panels had no handle at all.
  • The animations obey the system now, not only the transitions (#423).
  • Sync recognises a project both machines already had. Each added the folder before sync was on, so each made its own id and the arriving record looked like a second project. The deck matches on the folder’s git remote — the one string that is the same on both machines, and not necessarily called origin — and asks rather than deciding (#348, #359, ADR-0007, ADR-0010). The memory corpus travels with everything else, so a mistake caught on one machine is there on the other.
  • One instance per config directory (#361, ADR-0012). Two copies each ran their own sync cycle against one git repository; the second launch now focuses the first.
  • Store writes are atomic (#145) — temp file, sync_all, rename. A torn write left a zero-byte file and the next save made it the truth.
  • The audit is remediated. An outside pass on 2 September produced #463, and it is closed: two faults that could kill the app, six tray items dead on Linux, the English-only rule actually applied across 142 Cyrillic lines in fifteen Rust files, four files that had no tests, and the ADR numbering, which had collided twice.
  • The gates are gates. npm run contrast exits non-zero and now runs in CI (#455) — three green ticks could sit over a contrast regression before. Clippy is a gate at -D warnings, the crate having reached zero. And npm run adr:check catches a duplicate number, a heading that disagrees with its filename, and a dead link into docs/adr/.
  • CONTEXT.md is the vocabulary the README, CLAUDE.md and the ADRs are written in: what separates a tile from a session, a workspace from a project, a note from a fact.

Fixed

  • A clean checkout could not build the app: bundle.externalBin declared the memory sidecar and beforeBuildCommand staged two of three — and the release job runs exactly that build (#460).
  • After /clear, a restart and auto-restore resumed the pre-clear conversation and orphaned the real one (#199).
  • A session interrupted with Escape stayed stuck in the working state (#333), and Escape typed inside a terminal unzoomed the deck instead of reaching the program (#269).
  • An unpinned scheduled scenario ran in whichever workspace happened to be active at 03:00 (#249).
  • Deleting a workspace warned about its scenarios but not about its running sessions (#250), and the question named two sessions identically when their default name was the same (#458).
  • Switching workspaces forgot which session was zoomed (#224); zooming one collapsed the left panel, and re-collapsed it every time — the panel is the person’s to hide (#480).
  • A session’s displays were frozen at the launch directory, so changing folder or worktree inside the session changed nothing (#508).
  • Returning to a session left its scrollbar at the top, and the first wheel tick jumped into the scrollback (#340).
  • The deck’s five-second poll was not focus-gated, unlike the board and pull request polls beside it (#251).
  • Closing a workspace’s last session left its row in the sidebar (#358), and deleting a workspace took the main window with it, leaving the process running without one (#349).
  • A workspace window pinned to a workspace the store had lost kept its sessions under “Other” and offered no way to start one (#369).
  • The status dots blinked rather than breathed on macOS, and restarted every five seconds (#345).
  • The settings window was smaller than the settings it held (#391).
  • The limits shared the panel’s foot with a growing sessions island; the reading is in the top bar now, so it is there when the panel is collapsed — which a limit is not a property of (#392, #461, #498).
  • A session was told it had a memory and reached for the repository anyway (#388); the sidecar loaded the model once per search (#389).
  • Shift+F6 was undiscoverable — prev-region had no palette entry (#270).
  • Four flaky tests that failed on a loaded runner rather than on a fault (#284, #337, #448, #457) — each now waits on a handshake or a measured time rather than a clock.

Not in this release

  • A terminal still does not follow its workspace out of the main window (#479). The hand-off carries deck tiles only; a drawer shell stays in the window the workspace has left. It was closed during the milestone pass and reopened while these notes were being written, because nothing had fixed it.
  • Notes for the other CLIs. Only Claude Code sessions get one (#371, #372), and what a capture costs is still sampled at one call (#379).
  • Codex’s and Gemini’s limits. Their dials are in the lineup, dim, saying coming soon.
  • Frame rate (#261). Dragging a grip or resizing the window gives up three quarters of the display’s frame rate. Measured next, with the work that follows from the measurements.

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

That wording Gatekeeper uses — “the app is damaged” — means the bundle is not notarized, not that anything is wrong with it. There is no paid Apple Developer account behind this project yet.

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.

Upgrading from 0.5.x — nothing to do. Your workspaces, scenarios and sessions are read as they are, and no existing setting changes meaning. Two things are off until you ask for them, and both spend something: session notes cost a model call on your own Claude account, and are not written until you answer the question at a session’s close; searching them needs a 479 MB model, offered on the Memory page rather than fetched behind your back. The limits read claude’s own accounting every few minutes — switch that off in Settings if you would rather nothing started a short-lived process to ask.