Version pinned to 0.0.1 and staying on 0.x while this is in beta.
`npm run ship` now exports twice from one build: /Applications/Work.app
to test here, and ~/Desktop/Work-<version>.zip to send someone. One
build, so a tester runs byte for byte what was verified rather than a
second build that drifted. Packed with ditto rather than zip - a plain
zip mangles the bundle's symlinks and it will not open on the far end.
Settings: groups move up under apps, and the hidden-element list moves
into its own window behind a one-line summary. It had grown to 21
selectors of framework class names and was most of the page, in front of
the things people actually open Settings for.
Reset puts apps, groups, hidden elements and zoom back to defaults, and
leaves sessions alone - those live in WebKit's own store, and throwing
them away would mean signing back into every tool to undo a change to
the nav.
A child webview is positioned against the window frame while the shell
measures the hole it left from inside the content view. Borderless, those
origins coincided and it never showed. With a title bar back they are a
title bar apart, so every app was drawn that much too high - painting
over the right-hand part of the bar, which read as the bar being tinted
by whichever site was open, and leaving a strip of the same height along
the bottom.
Tauri cannot report that height. Both inner_position/outer_position and
inner_size/outer_size come back identical on macOS - measured, both
differences were zero against a window whose content is plainly a title
bar shorter than its frame. NSWindow.contentLayoutRect knows, so it is
asked once and cached.
Also hides the window title, and centres the navigation row in its own
strip rather than letting it crowd the bar above it.
Both previous attempts asked a question about a domain, and a domain does
not know which product it is serving. Google's favicon service returned a
marketing site's icon for anything behind a login and nothing for a
private host; Simple Icons returned one flat brand mark where the real
one is multicoloured and, for Gmail, carries the unread count.
The page already holds the answer - fetched, authenticated, current. The
injected script now reads link[rel~="icon"] and reports the best one:
largest declared sizes wins, an Apple touch icon counts as 180, and an
.ico is penalised as usually the 16px tab icon. It rechecks on the same
tick as the unread count, which is when a site like Gmail redraws its
icon with a badge. The URL is stored, so the nav is right at launch
rather than blank until every page has loaded.
The custom frame is gone with it: ordinary macOS title bar, traffic
lights where every other window puts them, and the bar following the
app's Light/Dark choice through set_theme. A window that behaves like a
window beats one that looks bespoke.
Simple Icons publishes each brand's own hex next to its glyph, and the
build was throwing it away. Tiles now carry it - Gmail red, Drive blue,
Chat green, Gemini violet - and the glyph is drawn black or white by the
tile's perceived brightness, since brand colours are picked to look right
rather than to carry a white mark. GitHub and Notion are near-black,
Snapchat is pure yellow, and a fixed white glyph loses one end of that.
An app's right corners are now rounded on its own layer. The container's
rounded-xl could never have clipped them: an app is a native view sitting
on top, not something the shell lays out, so it kept square corners and
overhung the curve. Only the right pair - the left edge butts against the
nav, and rounding it would notch the middle of the window.
The traffic lights move to (26, 24) and the drag strip deepens to match,
so they sit inside the window's margin instead of against its corner.
Adds Gemini, Claude, ChatGPT, Linear, ClickUp, HubSpot, Shopify and
Cloudflare to the host table.
The favicon service was wrong as often as it was right: a sign-in page's
icon for anything behind a login, nothing at all for a private host, and
both answers cached past any way of asking again. Refreshing could not
fix it, because the staleness was not local. Now every mark is.
Each app is its brand glyph in white on a round tile, coloured from
Tailwind's 500s by hashing the host - you find things by their colour, so
one that moved every launch would be worse than none. A host with no
glyph gets its initial in the same tile.
Matching tries the registrable name first, since a self-hosted tool is
nearly always on a subdomain of its vendor - aputure.odoo.com is Odoo,
not Aputure. A short table covers what a domain cannot answer, which is
most of Google.
The build reduces Simple Icons' 15MB of SVGs to one 4.5MB map in public/,
fetched once rather than parsed into the bundle at every start; the
bundle stays at 233KB. It is generated on every build, so never committed
and never stale.
Traffic lights are offset to sit inside the window margin rather than
crowding its edge.
A Tauri 2 shell with one child webview per configured tool. Nav on the left
with groups and a collapsible icon rail; links between configured apps switch
tabs, everything else leaves for the real browser.
Design spec in docs/superpowers/specs/2026-09-01-work-app-design.md.