Changelog

What we shipped.

Every release, documented. No marketing fluff — just what changed and why.

v1.5.17

2026-04-20

When Apple sign-in succeeds but the pairing tunnel can't come up — corporate firewall, TLS-intercepting proxy, managed-Mac file block — Push now tells you so, immediately, with the specific cause and something actionable to send to IT.

What's changed

All post-sign-in failures produce the same honest UX

Previously, only one of the three common corp-Mac failure modes (the managed-Mac local-write case) auto-opened a dialog explaining what went wrong. The other two — corporate firewall blocking push-relay.com, or a TLS-intercepting proxy breaking our handshake — landed silently in the pairing-status endpoint and the only user signal was a quiet red relay dot in the sidebar corner. Browser said Success, sidebar showed your avatar and name, and there was no obvious reason the iPhone still couldn't find the Mac.

1.5.17 closes the loop.

After a successful sign-in poll, the Mac briefly watches the pairing tunnel come up (up to ~4s). If it enters a blocked state — network unreachable, TLS verification failure, auth rejection, or a 5xx from our pairing server — the failure sheet auto-opens immediately, while you still have the browser's "Success" page fresh in mind. The sheet carries per-case copy: the actual fs path when it's a local write, the specific firewall hint when it's a network block, the TLS exclusion guidance when it's a proxy re-signing certs. The same diagnostic you'd need to hand your IT team is right there, copy-selectable.

Sidebar now honestly reflects what's working

Before 1.5.17, a sign-in that succeeded server-side but failed to bring up the tunnel left the sidebar showing "you're signed in" (avatar + name + red dot). That matched what the config file said, not what the user actually cared about — their iPhone still can't reach the Mac.

Now the sidebar branches on "effectively connected" instead of "api key present." If the sign-in didn't bring up the pairing tunnel, the footer collapses back to the same blue "Connect Apple Account" button a fresh install shows, plus an orange info-i that re-opens the failure sheet. The api key stays in config so a retry after IT unblocks doesn't need a fresh Supabase round-trip, but the UI stops claiming success until the tunnel is actually up.

Net effect: a user hitting any of the three known corp-Mac walls sees the same shape. Sign-in button, info-i beside it, auto-opened sheet with specific cause. No guessing which surface has the real information.

Notes

  • No data migrations. No user action required beyond updating.
  • The sheet's network/TLS copy is new; the existing local-save copy is unchanged from 1.5.11.
  • Full investigation and case taxonomy: push/macos/investigations/2026-04-20-corp-mac-pairing-failure-taxonomy.md.

v1.5.16

2026-04-20

Settings window gets a proper detail toolbar: browser-style back/forward chevrons on the leading edge, the current pane's name as plain text beside them — the same chrome shape Xcode Settings uses on macOS 26.

What's changed

Back/forward navigation in the Settings detail column

Sidebar taps now push onto a history stack. Two chevron buttons sit at the leading edge of the detail toolbar and shift a cursor through that stack — exactly like the back/forward buttons in a browser. Each chevron is its own ToolbarItem so Tahoe renders them as two distinct glass capsules with a divider between (rather than the fused pill ToolbarItemGroup produces), matching Xcode Settings.

Programmatic sidebar moves are guarded by an isNavigatingHistory flag so using the chevrons doesn't re-push the same entry.

Pane title rendered as plain text, not a toolbar button

The current pane's name (Apple Account, Integrations, etc.) now appears as plain text immediately after the chevrons. Liquid Glass backing is stripped via .sharedBackgroundVisibility(.hidden) (macOS 26+), and the title uses .title3.weight(.semibold) — the same weight Apple uses for Xcode Settings pane headings.

Settings scene: plain Window(id:) instead of Settings {}

SwiftUI's Settings {} scene silently ignores .windowStyle(.hiddenTitleBar) and most resizability / toolbar modifiers, which is why 1.5.15 needed an AppKit bridge to match the main window's nestled-traffic-lights chrome. 1.5.16 switches to a plain Window("Settings", id: "settings") scene that honors those modifiers natively — no bridge required.

Cmd+, is rewired via CommandGroup(replacing: .appSettings) + openWindow(id:), with NSApp.activate(...) first to handle the menu-bar-extra activation quirk. .toolbar(removing: .title) replaces the old titleVisibility = .hidden AppKit tweak.

Notes

  • No data migrations. No user action required beyond updating.
  • Behavior of every Settings pane is unchanged — this release only reworks the window chrome and navigation affordances.

v1.5.15

2026-04-20

The Settings window is rebuilt as a native macOS 26 sidebar — same shape as Xcode and System Settings — and the sidebar's connection popover now tells you about your paired iPhone, not just your Apple Account.

What's changed

Settings window: native macOS 26 sidebar

Push Settings used to be a single scrolling stack of glass cards. 1.5.15 ports it to the System-Settings / Xcode layout: a NavigationSplitView with a permanent left sidebar — Apple Account, Integrations, Coder Agent, Appearance, Server, Status, Uninstall — each driving its own pane on the right.

To get the Xcode look — sidebar extending edge-to-edge with traffic lights nestled inside it — SwiftUI's Settings {} scene needs the backing NSWindow reconfigured for full-size content view + transparent titlebar. A small NSViewRepresentable bridge does that once on attach. The window is resizable and supports full screen, but the sidebar-collapse button is hidden (Xcode's Settings doesn't have one either) and the sidebar can't be dragged closed.

Every pane uses native Form layout

Every pane is now Form(.grouped) with LabeledContent rows, so alignment, spacing, and section chrome come from SwiftUI itself rather than hand-rolled boxes:

  • Apple Account: dropped the glass-wrapped VStack and the redundant header row. Status, Apple ID, Owner ID, and iPhone are LabeledContent rows; Relay tunnel sits in its own section.
  • Integrations: custom HStacks replaced with LabeledContent { buttons } label: { Label + caption }.
  • Coder Agent: flattened the mixed header/status into a single Section("Setup") with a Status row.
  • Uninstall: removed the custom circled-number badges and the blue notice box. Two native Sections instead.

The result reads the same way Apple's own settings windows do.

Settings window chrome no longer doubles on macOS 26

The first cut of the new Settings window also attached an empty NSToolbar() with .unified style. On macOS 26, an empty unified toolbar still reserves ~44–52pt of chrome — so the Settings window had a top band roughly twice the height of the main window's. Fixed by matching the main window's pattern: transparent titlebar + full-size content view, no toolbar.

Sidebar connection popover: iPhone pairing state

The avatar popover that shows Account / iPhone / Pairing tunnel now actually tells you about your iPhone. The iPhone row is two-line, mirroring the Account row: device name on top, "Last active X" caption below. The "active" timestamp is parsed from the lastUsedAt already returned by /api/devices — it's request-driven (bumped when the iOS app talks to the server), not a heartbeat, so it honestly reads as "app last talked to the server."

The status indicator also gets smarter: when the relay is up and an iPhone is registered, the green dot becomes iphone.badge.checkmark — a green check on a secondary phone glyph. So "fully set up" reads visibly different from "ready, nothing paired yet." All failure states (amber retrying, red blocked, gray unknown) keep the dot regardless of iPhone presence.

Notes

  • No data migrations. No user action required beyond updating.
  • All Settings panes that existed in 1.5.14 still exist; they've moved from scrolling cards into named sidebar entries.
  • The Settings window is resizable and supports full screen now; previous version was fixed-size.

v1.5.14

2026-04-20

Reconnecting Apple Account after a disconnect now actually reconnects. Plus smaller polish around the connection popover and a confirmation when disconnecting.

What's changed

Disconnect + reconnect actually re-pairs

Before 1.5.14, hitting Disconnect on the Apple Account card would correctly tombstone your relay instance on our servers and strip the token from your local config, but it left the in-memory WebSocket tunnel still running and still pointed at the now-dead instance. When you hit Connect again, the server short-circuited ("tunnel's already up, nothing to do") and the zombie tunnel just kept retrying with a token the relay had already invalidated — every upgrade got a 401 back, the UI sat on "Connecting…" for as long as you left it open, and the only way out was to quit and relaunch Push.

1.5.14 adds a proper teardown path: Disconnect now closes the live WebSocket, clears the in-memory relay token and the retry schedule, and wipes the activation-error state so the pairing row doesn't report stale warnings. Reconnect runs a real fresh registration, so your Mac gets a new push-relay.com subdomain within a second or two.

Confirm before Disconnect

Disconnect is destructive — it tears down the relay tunnel, revokes the device pairing, and takes a re-register flow to walk back from. Clicking it now presents a native macOS alert with a red Disconnect button and a Cancel. Accidental clicks don't silently wipe the pairing anymore.

Sidebar connection popover polish

Three small cleanups on the avatar popover that shows Account / iPhone / Pairing tunnel:

  • Widened to fit a full push-relay.com subdomain inline with the label, instead of wrapping onto its own line with a blank first row.
  • The popover now sizes to its actual content height. The old fixed height left a tall empty zone below the rows after earlier UI slimming.
  • Removed the "Open Settings…" footer button. The popover is now a pure information surface; the Settings window is already reachable from the app menu and ⌘,.

Background — relay domain cutover finished

1.5.13 shipped the paperclip-relay.com → push-relay.com migration with both zones accepted as a safety net. 1.5.14 removes that safety net: the relay worker now only serves push-relay.com and only accepts tokens minted for that audience. If you upgrade straight from 1.5.12 or earlier and see "Pairing retrying" after first launch, disconnect and reconnect your Apple Account in Settings — your Mac will re-pair on push-relay.com immediately.

Notes

  • No data migrations. No user action required beyond updating (unless you're coming from 1.5.12 or earlier and have a paperclip-relay pairing still cached — see above).
  • The Supabase mint function's aud claim flipped to push-relay.com in the same cutover; no cross-client coordination needed.

v1.5.13

2026-04-20

A relay domain migration and a Spotlight-style popup terminal.

What's changed

New relay domain: push-relay.com

The pairing tunnel that connects your Mac to your iPhone used to run on paperclip-relay.com — a leftover from before the rename. We've moved it to push-relay.com so the domain matches the product.

After updating, your Mac will re-pair against the new relay on next sign-in or Apple Account reconnect. Existing iPhone pairings may need a one-time re-pair from Settings. During the transition the old zone is still accepted server-side, so there's no hard cutover — but all new installs and re-pairs land on push-relay.com going forward.

If you're on a corporate network, the firewall/TLS-inspection allowlist should now include *.push-relay.com (in addition to *.supabase.co). The pairing-status hints in Settings call this out with the new host.

Alongside the domain move, minted subdomain IDs went from 5 characters to 12. That's mostly invisible — the URL your iPhone talks to just looks like d4lsc5k8m2xp.push-relay.com instead of d4lsc.push-relay.com — but it hardens the tunnel against both random collisions and guess-based scans by several orders of magnitude.

Popup terminal on double-tap ⌘

Push now ships a Spotlight-style floating terminal. Double-tap the Command key anywhere on your Mac and a nonactivating terminal panel appears, ready to type. Double-tap again to dismiss. The panel does not steal focus from your current app — hit the hotkey in the middle of whatever you're doing, run a command, dismiss, and the app you were in stays frontmost.

The PTY and its Claude Code session live under a dedicated long-lived surface, so the popup keeps your shell state across show/hide cycles the same way a regular tab keeps state across sidebar navigation.

Dev builds listen on double-tap ⌥ (Option) instead of ⌘ so both variants can run side-by-side without fighting over the same keystroke.

Notes

  • The Cloudflare worker accepts JWTs minted for either paperclip-relay.com or push-relay.com during the transition, so there's no coordinated flag-day.
  • No data migrations. No user action required beyond updating.

v1.5.12

2026-04-19

Reliability fix for the class of bug where your Mac thinks it's signed in but your iPhone can't find it — and now you can actually see why.

What's changed

Settings clearly tells you what's wrong

Before 1.5.12, a Mac that hit any of several fragile edges during first-time sign-in would end up in a confusing in-between state: the browser said "Success," but the Mac's Settings still showed "Connect Apple Account," as if nothing had happened. Meanwhile your paired iPhone was never going to find it. There was no way from inside the app to tell whether you were signed in, whether the relay tunnel was up, or why anything was failing.

The real cause in the wild turned out to be two different failure modes wearing the same disguise. First, Apple Sign-In can succeed server-side (your account is linked) while the local write of the session fails — a managed Mac with EDR or MDM file-access policies can quietly block the config save. Second, the pairing tunnel to paperclip-relay.com can be refused by a corporate firewall or broken by a TLS-intercepting proxy (Zscaler, Netskope, and friends). In either case the old app showed the same blank "not connected" screen and the tunnel stayed offline forever.

Now Settings distinguishes three sign-in states and shows the actual reason when anything's wrong.

Signed in on servers but local session missing. The Mac asks Supabase "do you already have a registered instance for me?" using its stable fingerprint. If the answer is yes and local is empty, Settings shows a new "Re-sign in to restore" card instead of looking like a fresh install. Sign in once and everything syncs back.

Pairing status row. A new row inside the Apple Account card reports the tunnel state separately from the sign-in state. Three states: connected (with the actual subdomain), retrying (with attempt counter), and blocked (with a specific error hint and a Retry now button). Blocked states map to actionable guidance — "ask IT to allow *.paperclip-relay.com over 443" for a firewall, "ask IT to exclude our hosts from TLS inspection" for a corporate proxy.

Specific save-failure errors during sign-in. If the browser sign-in succeeds but writing the session to disk fails, you now see the actual reason (EACCES from MDM, ENOSPC, etc.) with guidance to check managed-Mac policies — not the old generic "Connection timed out" message five minutes later.

Hardened session persistence

The post-sign-in write now goes through a temp-file-plus-rename path and verifies by re-reading. If the write succeeds silently but the verify fails, we surface that instead of returning a 500 the UI couldn't decode. Corporate Macs with aggressive file-access policies will now fail loudly at the moment of failure rather than ending up in the desync state on subsequent launches.

Notes

  • A new Supabase edge function (lookup-instance-by-fingerprint) handles the server-side reconciliation lookup. Deployed server-side; no Mac-only migration needed.
  • No user-facing API changes, no data migrations.
  • Users on 1.5.11 or earlier who were already desynced will be auto-detected on next Settings open and prompted to re-sign-in.

v1.5.11

2026-04-19

Bug-fix release — kills the "claude sits on the prompt and never runs" flake when you spawn a Claude Code session from the + button or ⌘T.

What's changed

"New Claude Code Session" actually runs every time

Since the Claude auto-spawn landed, the + button (and, as of 1.5.9, ⌘T with Claude as default) would occasionally open a tab with claude typed at the prompt but never submit — cursor stuck on the word, no Claude Code banner. Quitting and relaunching the app papered over it until the next slow tick.

Root cause. Auto-spawn queued claude\n into the tab's PTY on the first prompt-ready signal. The trailing \n went through ghostty's text path, which bracket-wraps multi-line writes once the shell has enabled bracketed-paste mode. When main-queue scheduling landed the write after zsh's line editor turned bracketed-paste on, the \n arrived as a literal newline inside a paste block instead of firing accept-line. Whether you hit the race depended entirely on how loaded the main loop was at shell startup — hence the random failures.

Fix. Split the write: claude goes through the text path as before, then a synthetic Return key press goes through the key path. The key path is never bracket-wrapped — ghostty's input encoder emits CR, zsh binds ^M to accept-line unconditionally — so the submit is deterministic whether the shell's line editor is up or not.

No behavior change in the common case; existing installs just stop flaking.

Notes

  • No API or data-format changes; upgrade is transparent.
  • Same fix pattern applies to any future "auto-type a command" path (for example, adapters beyond Claude Code): send the text, then press Return as a key event. Don't embed \n in the text write.

v1.5.10

2026-04-19

Small but important reliability fix for first-time pairing.

What's changed

Mac-signed-in now guarantees iPhone-ready

Before 1.5.10, if the very first handshake with the relay hit any transient issue (network blip, relay hiccup, or — most commonly — a rate-limit backoff from the pairing service), the tunnel stayed offline and the only way to recover was quitting and relaunching the Mac app. The Mac thought it was paired; your iPhone saw nothing.

Now the Mac keeps trying in the background with exponential backoff (30s → 1m → 2m → 5m → 10m cap) until the tunnel comes up. Also raised the pairing rate limit from 5 to 100 mints per day so normal reconnection cycles don't trip it.

The net UX contract: once your Mac has signed in with Apple, your iPhone can sign in with the same Apple ID any time later and pair automatically. No restart required on either side.

Notes

  • Existing installs picked up the rate-limit bump silently (server-side).
  • No new integrations, no data migrations.

v1.5.9

2026-04-19

Small polish release — a new preference for what the tab + button spawns, plus a tidier default workspace name.

What's changed

Choose what + (and ⌘T) opens

The tab strip's + button used to hardcode "new terminal tab", with a right-click menu offering Claude Code as a one-off. That menu is now a setting, not an action:

  • Right-click the + → "Set default new tab option" with two checkmarked rows:
    • Terminal Tab (default)
    • Claude Code Session
  • Left-click the + and ⌘T both dispatch through the chosen default — flip the preference once and both entry points follow.

The + glyph itself mirrors the choice so you can tell at a glance what a click will do: the plain plus icon for Terminal Tab, the pixel-art Claude adapter character (same one you see in agent avatars) for Claude Code Session. Menu rows are plain text on purpose — the checkmark is all the signal the menu needs.

Default workspace name is "Workspace"

The onboarding quick-setup defaulted to "Push Workspace", which reads as repetition inside a Push app. It's now just "Workspace". Existing workspaces are untouched; the pu CLI and /pu skill still map both "Workspace" and legacy "Push Workspace" to the PU issue prefix so nothing downstream breaks.

Notes

  • Existing installs keep whatever default they had (the preference reads as Terminal Tab on first launch of 1.5.9).
  • No server-side changes beyond the workspace-name/prefix mapping.

v1.5.8

2026-04-19

Big onboarding cleanup + several relay/pairing fixes that landed since 1.5.7.

What's changed

Onboarding trimmed to 4 steps, zero engineer-speak

The old flow had five screens, two of which asked nothing of you — a 10-row pu setup checklist that ran through system-health probes under engineer-facing names ("Check the /pu skill", "Detect-cwd"), and a three-card finish screen that duplicated things you'd already seen. Both are gone.

Now:

  • Welcome — hero screen, one button
  • Finish setup — CLI shortcut + optional Launch at Login (the only step that asks you anything about the Mac itself)
  • Sign in with Apple — primary path; a small secondary link ("Use Push locally without iPhone") lets you skip if you don't want an iPhone connection
  • You're all set — single confident line, one CTA, you're in the app

The agent-provisioning script still runs (same pu setup), just silently in the background while you're clicking through. By the time you reach step 3, your default agent is set up and a starter task is seeded.

Back buttons now work on every step (hidden during the Apple sign-in browser round-trip so clicking back doesn't orphan an open auth window).

Relay activates in-process after Apple Sign-In

Before 1.5.8, a fresh install required a manual restart of the Mac app before the iPhone could connect — boot-time relay registration fired before Apple Sign-In had completed, failed, and nothing re-triggered it. Now apple-connect kicks the registrar the moment sign-in succeeds, so the tunnel is live without touching anything.

Apple email visible in Settings

The Settings → Apple Account card used to show only an opaque Owner UUID (80bf601c-8de…). It now shows the email you're connected as (e.g. you@example.com), pulled from the Supabase auth row. Existing installs show the email after the next sign-in or disconnect/reconnect cycle.

Dev/prod boot parity

Historical dev seed wrote deploymentMode: local_trusted to let the CLI pu setup short-circuit auth; that created a dev/prod divergence where dev needed a restart after Apple Sign-In and prod didn't. Dev now seeds relay mode by default. Internal cleanup; not visible to end users.

iOS sync fix + settings ghost-entry cleanup

  • iOS instances list used to accumulate stale "Pending setup" entries when the Mac re-registered under a new relay subdomain (e.g. after a disconnect). iOS now reconciles local cache against Supabase on each auto-connect, pruning local rows and their Keychain tokens when they're no longer in the authoritative list. (iOS change; ships with the next App Store/TestFlight build.)
  • Relay allowedHostnames guard now picks up subdomains added at runtime. Previously a fresh first-sign-in hit a 403 ("hostname not allowed") until the next restart.

Notes

  • No new integrations. Existing Apple Sign-In users don't need to re-pair.
  • deploymentMode: "local_trusted" is no longer the onboarding default anywhere — prod defaults to relay, dev seeds relay. local_trusted is still a valid mode for advanced users who set PUSH_DEPLOYMENT_MODE explicitly.

v1.5.7

2026-04-19

Fixes a real-time sync bug between the iPhone app and the Mac UI.

What's changed

Marking a to-do complete on iPhone now updates the Mac instantly

Before 1.5.7, completing a to-do on the iPhone would save to the server but the Mac UI wouldn't move the card to the Done column until you quit and relaunched the app. The reverse direction (Mac → iPhone) worked fine, which is what made the bug easy to miss: one direction of the sync was silently dropping every event.

The cause was a case-sensitivity mismatch in the live-events channel. The Mac app subscribed to its workspace's event stream using the uppercase form of the workspace UUID (Swift's default), while the server published events using the lowercase form (Postgres's default). The channel dispatch in Node's event system uses strict string matching, so the Mac's listener was never called. HTTP lookups survived the mismatch because Postgres normalizes UUIDs internally — only the real-time path was affected.

The fix normalizes the workspace UUID on both sides: the server lowercases on publish and subscribe (defensive against any client), and the Mac client now lowercases its subscription URL to match the iPhone's existing behavior.

If you had the first Mac paired and a to-do marked on iPhone refused to update, it will now update live.

For developers

  • server/src/services/live-events.ts — added channelKey() canonicalization around publishLiveEvent and subscribeWorkspaceLiveEvents.
  • desktop/Sources/Push/Networking/PushWebSocketClient.swift — lowercased workspaceId.uuidString in the WebSocket URL, matching push-ios/App/Push/PushWebSocketService.swift.
  • New reference doc: writing/documentation/push/macos/LIVE-EVENTS.md describes the realtime protocol, event types, and the UUID-case invariant with this bug as a worked example.

Installation

  • Download Push-1.5.7.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.6

2026-04-19

Security and pairing hardening. No new UI; everything improves quietly in the background.

What's changed

Multi-Mac pairing actually works now

If you signed in on a second Mac with the same Apple ID, the second registration silently overwrote the first — your iPhone would unknowingly start talking to whichever Mac signed in most recently, and the first Mac would drop off your phone's paired list. Under the hood, Push's discovery table enforced one row per Apple account.

That constraint is lifted. Each Mac now registers its own row, keyed by a stable UUID that lives in the Mac's own data tree. Your iPhone's Settings → Push shows every paired Mac and lets you switch between them. Prod and dev builds on the same machine also coexist cleanly — they're separate data trees, separate rows.

If you already have one Mac paired and it just keeps working, you won't notice anything. You don't need to re-pair.

Pairing auth redesigned to drop the shared secret

The relay that bridges your iPhone to your Mac used to accept new instances via a shared secret baked into the Push build. That model couldn't ship to the public — the secret would leak from any distributed binary. Replaced with a per-session token minted by the Push backend after Apple Sign-In, valid for 60 seconds, bound to the relay's audience and your Apple identity. Same industry-standard shape as ngrok's authtoken, cloudflared login, and Tailscale's SSO pairing.

Invisible in use. The only visible consequence: a fresh install from a public DMG now registers successfully where it would have failed before.

Clean disconnect

Signing out of Apple from Settings → Apple Connect → Disconnect now:

  • Removes the Mac's entry from the discovery table (previously left stale until you wiped the Mac's data tree).
  • Deregisters the relay subdomain and tombstones it so the subdomain can't be reinherited by a future install.
  • Strips the relay token from the Mac's local .env so the next launch mints a fresh one.

Existing disconnects before 1.5.6 left breadcrumbs you may still see in your iPhone's picker; removing them requires a one-time toggle (Sign out of Apple → Sign back in) on the affected Mac.

Stronger relay-side rate limits

Per-instance ceilings on push notifications (60/hour) and registered device tokens (20) so a misbehaving or compromised install can't spam under our Apple APNs key. Subdomain minting is random-only with a brand-name blocklist to prevent squatting.

Public abuse intake

A new POST /abuse/report endpoint on the relay accepts suspicious-subdomain reports from anyone. Reports are logged for human review. Preparation for opening the DMG to public download.

For developers

  • New Supabase edge functions: mint-relay-register-token, delete-push-instance. Existing register-push-instance updated to accept instance_fingerprint; legacy single-row-per-user callers transparently upgrade in place.
  • Relay Worker now serves /deregister, /abuse/report, and accepts either the legacy shared secret or the new RS256 JWT on /register during the transition window.
  • Design docs: push/macos/plans/2026-04-18-paperclip-instances-multi-row-rollout.md and push/macos/plans/2026-04-18-relay-auth-apple-signin-token-exchange.md.

Installation

  • Download Push-1.5.6.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.5

2026-04-19

Small terminal-strip additions.

What's changed

Right-click the + to start a Claude Code session

The + button above the tab strip now accepts a right-click. You get a two-item menu:

  • New Terminal Tab — same as the left-click (inherits the active tab's folder, opens your usual shell).
  • New Claude Code Session — opens a tab in the inherited folder and launches Claude Code for you.

The Claude option is deliberately not a shortcut through a new code path — it opens a regular terminal tab and types claude once the shell is ready. Every Push integration behaves identically to when you type it yourself: the tab's PUSH_TAB_ID binds to Claude's --session-id, the session marker is written, and the tab auto-resumes its Claude session after an app relaunch. Any custom flags you've pinned into your own claude() wrapper in .zshrc (like --dangerously-skip-permissions) still flow through.

Reopen closed — breathing room

When the tab strip overflows horizontally, the Reopen closed button on the right used to press right up against the last tab chip, visually reading as the strip's trailing end. Added a few points of leading padding so it registers as its own affordance.

Installation

  • Download Push-1.5.5.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.4

2026-04-19

Two small terminal-strip polishes.

What's changed

Reorder folder chips by drag

The folder-filter chips in the terminal toolbar (the row that starts with All) now accept drag-to-reorder. Grab a folder chip, drag it past a neighbor, and the siblings slide out of the way live under the cursor — same feel as dragging tabs in the strip below. All stays pinned to the first slot and can't be dragged. Your chosen order is persisted across app restarts, and if all tabs in a folder close and that folder later reappears, it snaps back to its remembered position.

Close icon fades on hover

Hovering a terminal tab to reveal its × close button used to pop the icon in and out instantly. It now fades over ~120 ms — gentle enough to read as deliberate, fast enough that flicking across tabs still feels snappy. The 14pt slot is always reserved, so the title text no longer nudges sideways when the icon appears.

Installation

  • Download Push-1.5.4.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.3

2026-04-19

Feed is now a weighted dashboard — a row of tappable glance-metrics at the top, decisions that need you underneath, activity and resolved history below. The separate Dashboard sidebar entry is gone: everything it surfaced now lives on Feed or is one click away. Under the hood Feed gained offline caches, a recoverable Cleared tray, actionable approval notifications, and optimistic actions that roll back with a toast when something fails.

What's changed

Feed is the dashboard

The old four-tab list (All / Action / Update / Approvals) is replaced by a single scrolling view with priority baked into the layout:

  • Metric row at the top — four square tiles: Decisions, Running agents, Open issues, and This month spend. Tap one to jump to the matching sidebar section (Sessions, Issues, Costs) or, for Decisions, scroll-anchor to the hero section below. Running agents gets a red error chip if any agent is in the error state.
  • Needs your decision (hero) — pending approvals, drafts, alerts, and deliverables rendered as amber-accented cards with inline Approve / Reject / Copy & Open actions. On Tahoe, primary actions use .glassProminent with an accent tint.
  • Recent activity — completions, artifacts, and other FYI items as muted secondary cards. Artifacts keep their inline file row with the same "View" affordance.
  • Resolved decisions — a tertiary archive of approved / rejected / cancelled approvals. Muted read-only tiles.

Every section auto-hides when empty. Search at the top of the window filters all three.

Dashboard is gone. Its counts — Active Issues, Pending Approvals, Agents Running, Month Spend — live in the metric row now. Completed issues are one click away in Issues. Cost utilization moved to Costs where it belongs. Running-agent list is covered by Sessions. If you had Dashboard pinned as your default launch section, Push silently routes it to Feed on next open.

Offline, on purpose

Feed now works when the server doesn't.

  • Cache-first render on launch. The last /feed response is persisted to ~/Library/Caches/<bundle>/FeedCache/; opening Feed shows the cached items instantly while the network refresh runs in the background.
  • Artifact pre-fetch. When the feed loads, Push quietly pulls the bodies of the top five artifact items into a local file cache. Tapping an artifact's View sheet after the server stops responding still renders its content.
  • Offline banner. A compact amber capsule sits above the hero whenever the server stops responding, with "Updated Nm ago" so you know how stale the visible data is.
  • Action gating per item. Approve and Reject buttons go disabled with a "Reconnect to act" hint when offline. Copy & Open, View file, and navigation keep working — they don't need the server.

Cleared tray — dismiss is recoverable

Every swipe or X-button dismiss now also writes to a per-workspace Cleared log. When anything is in it, a tray icon appears in the Feed toolbar; tap it to see what you've cleared and restore anything non-terminal (terminal here = approvals you already decided on; the server rejects un-deciding them). Stored for seven days, then auto-purged.

Optimistic actions + toasts

Every mutating action — approve, reject, dismiss, copy & open — now removes the item from the visible feed immediately. If the network call fails, the item pops back into place and a toast surfaces the error ("Couldn't approve", "Couldn't dismiss"). Copy & Open confirms with a success toast. No more silent failures. Toasts live in the bottom-right, auto-dismiss after three seconds, and respect Reduce Motion.

Actionable approval notifications

When an agent requests an approval, the system banner now carries three inline actions:

  • Approve — resolves the approval without bringing Push to the foreground
  • Reject — same, destructive styling
  • View — brings Push to the front and jumps to the Feed

Banners show the agent name, the approval title, and an optional description. Request IDs are deterministic per-approval so duplicate WebSocket events don't stack banners — you get one.

Smaller polish

  • First sidebar group (Feed / Issues / Terminal) no longer shows an "Overview" header. Workspace and Manage groups keep theirs.
  • Dismiss All is removed from the Feed toolbar. The Cleared tray is the safety net; per-row dismiss covers the rare inbox-zero case.
  • All HTTP calls feed a new server-status tracker. Transport failures flip the offline flag instantly; HTTP application errors (4xx/5xx) don't — the server did respond, just with a specific error.

Installation

  • Download Push-1.5.3.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.2

2026-04-18

Feed and Approvals are now one sidebar entry, the terminal tab right-click menu gains a Reload option, and secondary interactions on a tab chip are now scoped to the active tab on a frontmost app — consistent with the rest of macOS.

What's changed

Feed and Approvals, unified

Approvals was duplicating the feed — pending decisions were already surfaced there with inline Approve/Reject. 1.5.2 merges them into a single Feed sidebar entry with four tabs at the top:

  • All — everything.
  • Action — items that want your attention.
  • Update — status changes and notifications.
  • Approvals — the grouped pending/resolved board you know, with the tile layout and inline Approve/Reject decisions unchanged.

Search now filters across both domains. Dismiss All and swipe-to-dismiss remain scoped to feed items (they don't touch Approvals tiles). If you had Approvals set as your default sidebar section, Push silently routes that to the Feed view on next launch — no re-configuration needed.

On macOS 26 Tahoe the primary feed-row action and Approve tile button now use glassProminent with an accent tint, the approvals grid gets .soft scroll-edge treatment, picker counts render in monospaced digits, and the tile border is a notch firmer so tiles read clearly against the brighter material.

Reload a terminal tab in place

Right-click any terminal tab → Reload (also ⌘R when the tab is focused). The surface tears down and is recreated inside the same tab, keeping its UUID, position, title, and cwd. Claude sessions auto-resume via the marker file — same path as quit-and-relaunch, so the conversation picks up where it left off. Plain shells relaunch at the tab's last-known cwd. Browser-style reload semantics: the tab survives, the ephemeral process state does not (scrollback, foreground commands, shell variables).

Useful when a live theme switch leaves stale truecolor cells on screen (the TUI's own redraw is the only way to repaint them cleanly), when Claude gets into a wedged render state, or any time you want a fresh PTY without losing the tab slot.

Chip interactions behave consistently

Double-click rename and right-click context menu are now both gated on the same preconditions: the tab must be active and Push must be frontmost. Two concrete improvements:

  • Right-click on a terminal tab chip while Push is in the background no longer pops the context menu before the window has come forward. Matches Finder and Safari — a click on a background window brings it forward first, then you interact.
  • Right-click on an inactive tab no longer opens the menu at all. You select the tab first (single click), then act on the selection. Same "select, then edit" convention already used for double-click-to-rename.

Single-tap select continues to work everywhere, so tab switching is unaffected.

Installation

  • Download Push-1.5.2.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.1

2026-04-18

Hotfix for a serious 1.5.0 regression — Shift-modified keys (uppercase letters, @, #, $, %, etc.) didn't reach the terminal correctly. Plus two small terminal-workflow polishes that landed alongside.

What's changed

Shift keys work again in the terminal

1.5.0's Ctrl+C fix fed libghostty a keyboard field (unshifted_codepoint) on every keystroke. Ctrl+C got the fix it needed, but the same field silently perturbed Shift+<char> encoding — typing Shift+2 produced 2 instead of @, Shift+A produced a instead of A, and so on.

1.5.1 scopes the Ctrl+C fix to Ctrl+letter only. Non-Ctrl keystrokes (plain typing, Shift combinations, Cmd shortcuts, Option dead keys, arrow keys) now hit libghostty exactly the way they did in 1.4.0. Verified that Ctrl+C, Ctrl+D, Ctrl+L, Ctrl+A, Ctrl+E, Ctrl+W, Ctrl+U all still deliver their usual signals at bare zsh — the 1.5.0 headline fix is preserved.

If you're on 1.5.0, please upgrade immediately. The auto-update prompt should show within a few minutes; you can also force a check via the menu.

Reopen closed tab by name

⌘⇧T and single-clicking the Reopen closed button still pop the newest closed tab. Right-clicking that button now opens a context menu listing every tab on the closed-tab stack by name (newest first) — pick a specific session instead of popping one at a time hoping you'll land on the right one.

Folder-filter keeps your place

Two related polishes to the folder-chip filter in the tab strip:

  • Switching folders used to always snap to the first tab of the destination folder. Now it remembers the last tab you had active in each folder and returns you there.
  • Closing the active tab inside a filtered folder used to occasionally teleport focus outside the filter, leaving the chip and the visible pane disagreeing. Close now picks the closest in-filter neighbor so the chip stays honest.

Installation

  • Download Push-1.5.1.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.5.0

2026-04-18

Smoother first-run onboarding with a built-in iOS pairing step, plus a quiet fix to Ctrl+C at the terminal prompt.

What's changed

QR code for the iOS companion app

Onboarding now shows a TestFlight QR code right after Apple Sign-In. Scan it from your iPhone's camera to install the Push iOS app — no need to have it pre-installed. The onboarding step stays visible with a live status line that ticks over to ✓ the moment your iPhone pairs with your Push account. Skip it if you don't want the companion app; the desktop works fine on its own.

Silent setup, no more "Run this in Terminal"

The old onboarding showed a dedicated Setup step that flashed progress bars for the local server, database, workspace, and relay. It was noisy and the user didn't have to do anything during it. 1.5.0 runs all of that silently in the background while you're on the Welcome and Sign-In steps — by the time you reach the end, it's done.

The CLI install step also switched to a user-local symlink into ~/.local/bin (no sudo prompt, mirroring Claude Code's installer). If ~/.local/bin isn't on your PATH, the step shows a one-line snippet you can copy-paste (or a Run it button that does it for you) rather than silently editing your shell rc file.

Ctrl+C at the shell now delivers SIGINT

For months, pressing Ctrl+C at a bare zsh prompt in a Push terminal tab would sometimes show the literal characters 5u on the command line instead of sending SIGINT. Invisible inside Claude Code (which has its own key parser), but annoying the moment you exited Claude and typed a shell command. Traced to a mismatch between how macOS pre-translates Ctrl+letter and what Push's terminal engine expects — Push was handing it the already-translated byte, not the letter, so the encoder's lookup table missed. Fix aligns with the reference implementation used by cmux and similar tools. Ctrl+C, Ctrl+D, Ctrl+L, Ctrl+A/E, Ctrl+W, Ctrl+U all now work reliably at the shell.

Installation

  • Download Push-1.5.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.4.0

2026-04-18

Small polish release — the CLI startup banner now says PUSH instead of the old PAPERCLIP ASCII art left over from before the rebrand.

What's changed

PUSH banner in the CLI

The figlet banner that prints when the push CLI starts up still showed PAPERCLIP — a leftover from before the rename. 1.4.0 swaps it for PUSH, matching the product name everywhere else.

Purely cosmetic. No behavior change.

Installation

  • Download Push-1.4.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.3.1

2026-04-18

Small polish on the Appearance picker shipped in 1.3.0.

What's changed

Appearance picker icons now render in the default text color

The moon / sun / auto glyphs at the top of the color picker were inheriting the parent tinted-glass button's hue — a dark-red moon on a red tint, an orange sun on an orange tint, and so on. 1.3.1 forces the primary text color on each Appearance row's icon so the glyphs stay readable regardless of which tint you've picked.

No behavior change. Picking Light / Dark / System still works exactly as 1.3.0 shipped.

Installation

  • Download Push-1.3.1.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.3.0

2026-04-18

App-wide Light / Dark / System appearance override — the same per-app toggle pattern Apple ships in Xcode, BBEdit, and Mail, now inside Push. Pick one regardless of your global macOS appearance, and Push (plus the embedded terminal) follows.

What's changed

Light / Dark / System picker

The terminal toolbar's color picker now has a new Appearance section at the top with three choices:

  • System — follow your macOS Appearance setting (default)
  • Light — force light, regardless of system
  • Dark — force dark, regardless of system

Your choice persists across launches and is applied before the first window paints, so there's no flash of system-default appearance on launch. The override cascades to every SwiftUI view, AppKit panel, and the embedded Ghostty terminal — flipping Light or Dark immediately re-themes the terminal palette too.

Built on NSApp.appearance, the Apple-sanctioned hook for per-app overrides. Nothing about the system-wide Appearance setting is touched — only Push's own windows.

Cleaner picker menu

Fixed a stray-divider bug in the same menu where the Strength section showed two dividers between its header and the first row instead of one. Same fix applied to the new Appearance section so both read cleanly.

Installation

  • Download Push-1.3.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.2.1

2026-04-18

Bug-fix release. 1.2.0 introduced a regression where Claude sessions didn't auto-resume after quitting and relaunching Push — that's fixed here. Also bundles the embedded terminal's themes inside Push itself, so live light/dark palette switching no longer depends on having Ghostty.app installed.

What's changed

Claude sessions resume correctly on restart

1.2.0 shipped a bug where quitting and relaunching Push left restored tabs alive but empty — Claude didn't come back. This was a side effect of the new theme work colliding with an internal shell-integration mechanism; the collision silently dropped the per-tab identifier our auto-resume needs to bind each tab to its Claude session. 1.2.1 routes that identifier through a different path and restores the original behavior. Quit-and-relaunch now picks up Claude sessions the same way the in-app Resume button always did.

The in-app Resume / "Reopen Closed" buttons were never affected — they take a different code path that doesn't go through the shell — so if you'd been using those as a workaround, nothing changes for you.

Terminal themes bundled inside Push

1.2.0's live light/dark terminal palette depended on Ghostty.app being installed on your Mac (we used its bundled themes as a bridge). 1.2.1 vendors the theme files (Builtin Tango Light / Builtin Tango Dark) inside Push itself, so the feature works standalone on a clean machine. No behavior change if you already had Ghostty.app.

Installation

  • Download Push-1.2.1.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.2.0

2026-04-18

Terminal theme work — strength control for the section tint, live light/dark adaptation for the embedded Ghostty surface, and a text-contrast fix so tints don't wash out terminal output at higher intensities.

What's changed

Strength control for the terminal tint

The tint picker now has a Strength section under the color list, with ten discrete steps from 10% to 100%. Default is a conservative 10%, and your color and strength choices persist separately so switching hues preserves your preferred intensity. The Strength section gracefully disables itself when "Default" (no tint) is selected.

Text stays readable at any strength

Previously a high-strength tint washed out terminal output — white text at 50% tint turned cloudy because the overlay sat on top of everything. The overlay now uses .blendMode(.color) which preserves the underlying luminance while only swapping hue + saturation. White text stays white, black text stays black, and the mid-lightness materials (sidebar, detail pane, toolbar glass) pick up the tint properly. Same native SwiftUI primitive used by Apple's own tinted UI.

Polished pink + always-on color indicator

  • Pink was switched from systemPink (reads cherry/red through the blend mode) to a custom rose-pink (#E68BBE) that stays recognizably pink at all strength levels.
  • The toolbar picker button now shows the selected color at full saturation regardless of Strength — it's a selection indicator, not a strength preview. Strength still modulates the actual window wash.

Terminal adapts to macOS Light/Dark mode

The embedded Ghostty terminal now correctly swaps its palette when you flip System Settings → Appearance between Light and Dark. Previously in Light mode the terminal could render blank — text was white on a light NSVisualEffectView material. Fix required wiring up four pieces that Ghostty expects from embedded apps: the resources directory environment variable, a dual-theme config, a RELOAD_CONFIG action handler, and explicit surface refresh on config change.

This currently depends on Ghostty.app being installed on your Mac (we use its bundled themes as a bridge). A follow-up release will ship the themes inside Push itself so this works standalone.

Installation

  • Download Push-1.2.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.40

2026-04-17

Terminal polish and a stack of dev-variant isolation fixes that make internal iteration safer without changing prod behavior.

What's changed

Per-section tint in the terminal

Each terminal section can now carry its own tint color, picked from a glass-prominent toolbar picker that matches macOS 26 Tahoe's material language. The picker tints the capsule itself rather than a child icon, so the selected color stays readable regardless of button state.

Terminal tabs

  • Tab titles now reset on Claude Code /clear. The haiku-title OSC that Claude Code emits on startup was sticking around forever after a /clear, so every subsequent session kept the stale title. Push now watches the claude-running/<tab> session_id flip and drops prefix-stripped matches on reset.
  • Tab dividers no longer hide on hover. They stayed visible in all states for consistency.

Dev-variant isolation sealed end-to-end

Push ships as two coexisting bundles (ai.massless.push and ai.massless.push.dev) so the running prod instance hosting the agents is never killed during iteration. Three remaining leaks from dev into prod's data tree are closed:

  • The CLI's run-sidecar, launchd service, and onboarding-wizard agent scaffolder all respected $PUSH_HOME in some paths but still hardcoded ~/.push/ in others.
  • The onboarding wizard's SetupRunner shelled out to the global /usr/local/bin/pu symlink, which may point at a different variant's frozen bundle. It now prefers the bundle-local arch-specific CLI so setup stays in lockstep with the running Swift binary.
  • AppMover's "move to /Applications" prompt is gated behind skipsFirstLaunchOffers, so dev launches no longer nag to relocate.

None of this is visible from prod — the release pipeline is unaffected and your ~/.push/ tree is preserved across the update.

Installation

  • Download Push-1.1.40.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.39

2026-04-17

The file-preview crash is actually fixed this time. v1.1.38 shipped with an assumption that didn't hold in CI. This release vendors the syntax-highlighting dependency and bypasses the SwiftPM generator that was causing the crash.

What's changed

Syntax-highlighting engine vendored + loaded via our own bundle lookup

HighlightSwift is now vendored at desktop/Vendored/HighlightSwift/ — a local fork of v1.1.0 that drops the upstream resources: [.process(...)] declaration and replaces SwiftPM's auto-generated resource accessor with a 5-line BundleLocator.swift that looks up highlight.min.js under Bundle.main.resourceURL. mac-assemble-app.sh copies the JS file directly into Contents/Resources/.

The prior approach (patching the auto-generated accessor in the assemble script, then running swift build a second time) worked on a developer's Mac but didn't survive CI — SwiftPM's "Write sources" step regenerates the accessor on every rebuild, overwriting the patch. The vendored fork side-steps the generator entirely, so the bug can't regress no matter how SwiftPM behaves.

Side-effects:

  • Release pipeline is simpler: one swift build, one cp highlight.min.js, no sed-patching.
  • A build-time guard in mac-assemble-app.sh hard-fails if a new unvendored SwiftPM dependency ever ships resources — catches the same class of bug for future deps before they reach users.

Installation

  • Download Push-1.1.39.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.38

2026-04-17

Double-clicking a code file no longer crashes the app. Every version since v1.0.0 would fatalError when you opened a .ts, .js, .py, .swift, or any other code file from the Files gallery — or previewed a Markdown file with fenced code blocks. The syntax-highlighting engine was missing from the shipped .app; the fix ships it.

What's changed

File previews render without crashing

The file-preview pipeline was also rebuilt around a "fail closed to the next tier, never to a crash" design:

  • Tiered rendering: syntax-highlight → plaintext → fallback card. Every stage wrapped in its own do/catch so failure drops one tier instead of propagating.
  • Binary / long-line / oversize guards pre-filter before the highlighter sees the file, protecting against minified bundles, embedded base64, and pathological regex backtracking.
  • 2 s timeout on the highlighter — catastrophic-backtracking grammars can no longer hang the preview.
  • NSTextView-backed content view replaces SwiftUI Text for large files and long lines. TextKit handles arbitrary content sizes gracefully; CoreText layout crashes are off the table.
  • Per-call highlighter instance — the shared JavaScriptCore context is gone, so two concurrent preview loads can no longer corrupt each other's state.
  • Breadcrumb logging under subsystem: ai.massless.push, category: preview — future crashes leave a trail. Tail with:
    log stream --predicate 'subsystem == "ai.massless.push" AND category == "preview"'
    

Release pipeline hardened against this class of bug

The root cause was that SwiftPM's generated resource-bundle accessor looks for HighlightSwift_HighlightSwift.bundle at the top of the .app (alongside Contents/), but mac-assemble-app.sh never copied it there. Dev binaries happened to work because SwiftPM also bakes a compile-time absolute path as a fallback — and on the dev's own Mac that path resolves. CI-built binaries bake /Users/runner/work/... which doesn't exist on any user's Mac → fatalError on every first code-file preview.

This is the third instance of the same class of bug (after Sparkle v1.0.0, ghostty-shell-integration v1.1.16). The assembly script now carries an explicit copy step AND a post-assemble invariant that hard-fails the build if the bundle is missing. Release pipeline memory updated so SwiftPM resource bundles are treated as first-class shippable assets.

Installation

  • Download Push-1.1.38.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.37

2026-04-17

Terminal tab switching is instant again.

What's changed

Terminal: zero-latency tab switch

Clicking a tab activated it after a ~500 ms pause. The tab chip had both a single-tap (select) and a double-tap (rename) gesture recognizer attached, so AppKit had to wait the system double-click interval on every single click to rule out a double-tap. Modifier declaration order doesn't decouple that wait — the only fix is to never let the two recognizers coexist on the same view.

Inactive chips now carry only the single-tap recognizer; active chips carry only the double-tap recognizer. Selection is instant again. Double-click an already-active tab to rename it (matches Finder / Xcode "select, then edit" convention). Right-click → Rename… still works on any tab.

No hardcoded intervals — SwiftUI reads your system double-click speed from System Settings → Accessibility → Pointer Control at click time.

Installation

  • Download Push-1.1.37.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.36

2026-04-17

Drag or paste N images into a Claude Code session and all N render as attachments. Every drop lands in the tab you're looking at.

What's changed

Terminal: multi-image drop and paste now attaches every image

Dragging or ⌘V-ing two or more images into a running Claude Code session now renders each one as a [Pasted Image] attachment. Previously only the last image survived. Works for Finder multi-select, screenshot thumbnails, and path strings copied from other terminals. Paths under /TemporaryItems/ (macOS's screenshot-thumbnail temp dir) are now stabilized into our own temp dir before insertion so the floating-thumbnail reap race can no longer ghost an attachment.

Terminal: drops always land in the visible tab

Drops used to sometimes disappear — AppKit was hit-testing the drop onto a hidden tab's surface, silently filling a PTY you couldn't see. Drops now route to whichever pane is active, matching how ⌘V has always worked.

Approvals: sectioned gallery with inline decisions

The approvals queue now groups by section and lets you approve or deny inline without leaving the list.

Fixed

  • Double-clicking a skill tile no longer crashes the app.
  • Double-clicking a file tile no longer crashes the app; the gallery and preview layout got a round of polish.

Installation

  • Download Push-1.1.36.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.35

2026-04-17

The "Ready to install and relaunch" alert now tells you your Claude Code sessions are safe — right where the anxiety lives.

What's changed

Session-safety reassurance on the native relaunch alert

When an update is downloaded and Sparkle asks whether to install and relaunch, the alert body now includes:

"Your active Claude Code sessions will resume automatically after the relaunch — no work lost."

Sparkle doesn't expose the alert's body text through any delegate hook, so the copy is patched into Sparkle.framework/Resources/Base.lproj/Sparkle.strings at assembly time — English-only, drift-guarded (the build hard-fails if a future Sparkle upgrade renames the key rather than silently dropping the copy).

Same reassurance already shows in the earlier "Update Available" dialog's "What's New" pane via the release-notes banner; this release extends it to the second, higher-stakes dialog.

Installation

  • Download Push-1.1.35.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.34

2026-04-16

First release since the auto-update flow was fixed end-to-end — this is the one where you'll actually see the native "Update Available" dialog.

What's changed

Nothing functionally — this is a staging release to observe the corrected auto-update UX now that 1.1.33 is the baseline.

If you're running 1.1.33, within ~30 minutes of that version starting up your next scheduled update check will find this 1.1.34 entry, and Sparkle will surface its native "Update Available" dialog — without stealing focus from your active terminal — showing the reassurance banner and release notes in the "What's New" pane next to the Install button. Tick the checkbox if you want silent installs in the future; that preference now sticks across launches.

Installation

  • Download Push-1.1.34.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.33

2026-04-16

Fix to the 1.1.32 fix: the auto-update preference migration now runs exactly once instead of every launch, so ticking "Automatically install updates" actually sticks.

What's changed

Silent-install preference is respected again

1.1.32 cleared SUAutomaticallyUpdate=true from persisted preferences on every launch, which meant: if you saw the native "Update Available" dialog, ticked "Automatically download and install updates in the future" to opt into silent-install mode, and restarted Push — the next launch undid your choice.

Sparkle's own docs warn against re-writing this value on every launch (SPUUpdater.h:220). 1.1.33 gates the reset behind a one-shot marker key: the one-time correction for users who were stuck in silent mode from a past release still happens, but from then on your preference is respected.

If you want silent installs, tick the checkbox once on any future update dialog — it'll stay on across launches.

Info.plist cleanup

Removed SUAutomaticallyDownloadsUpdates from Info.plist. It was never a real Sparkle key — the canonical setting is SUAutomaticallyUpdate, which we already had. No behavior change, just removing dead configuration that made the intent unclear to future readers.

Installation

  • Download Push-1.1.33.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 15 Sequoia or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.32

2026-04-16

Auto-update relaunch dialog actually appears now — previously Push was silently installing on quit without any prompt.

What's changed

Auto-update now asks before relaunching

If you installed Push before 1.1.27, there's a good chance you ticked "Install updates automatically in the background" the very first time Sparkle asked — or it was on by default. That persisted preference was overriding every later setting and causing Push to silently download and install updates on quit with no dialog whatsoever. Every release from 1.1.27 through 1.1.31 went onto your machine without you ever seeing a prompt.

On first launch of 1.1.32, Push flips that stale preference off so the intended flow takes effect: silent background download, then the native "A new version is ready to install" dialog surfaces — with the "your Claude Code session will be saved and resumed" reassurance banner attached to every release's notes, right next to the Install and Relaunch button.

You can still re-enable silent installs anytime via the checkbox in Sparkle's own update dialog if you prefer the quieter path.

Appcast no longer double-encodes release notes

The release-notes banner on 1.1.28 through 1.1.30 was rendering as literal text (> **Your existing...**) instead of a markdown blockquote because each release was re-serializing past items and adding a layer of HTML escaping on top of what was already there. Fixed by switching the appcast writer to string-splice — existing items stay byte-for-byte identical, new items ship clean. 1.1.32 and every release after will render the banner correctly.

Installation

  • Download Push-1.1.32.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.31

2026-04-16

Smaller, sharper terminal: live slide-reorder for tabs, the active tab now uses your macOS accent color, and the Claude session-resume race after quit-and-relaunch is fixed.

What's changed

Live slide-reorder for tab drag

Drag a tab and the surrounding tabs slide out of the way in real time under the cursor — no more "drop blindly and the list jumps." Same convention as Safari and Apple Terminal. The dragged tab's chip fades to 30% so the floating drag image reads as the moving tab. Drop, escape, or drag-outside-the-app all clean up correctly.

Active tab uses the system accent color

Selected tab chip now fills with your macOS accent color at a soft 15% opacity instead of a neutral grey. Reads as a clearly "selected" pill against the strip's background and follows your Settings → Appearance → Accent color automatically. Inactive chips remain transparent.

Claude session resume after quit + relaunch is reliable now

Two corner cases were intermittently dropping you into a fresh empty Claude session after a Push quit/relaunch (or Sparkle auto-update relaunch) instead of resuming the conversation you were in:

  • You'd cd into a different folder mid-session. The auto-resume couldn't find the JSONL transcript at the new cwd's project slug and silently started fresh. Fixed by recording the session's home folder in the marker file and resolving the resume against that folder.
  • Marker file got half-written if Claude was killed mid-write. Now written atomically (temp + rename), so the marker is always either complete or absent — never partial.

The "fresh empty Claude session with the right title" symptom should be gone.

New tabs open at the leading edge

Open a new terminal tab and it appears at the start of the strip instead of the end. Most recent work sits where you're already looking — no chasing the rightmost tab.

Toolbar polish

The "Open new terminal in a folder" button in the toolbar now uses Apple's folder.badge.plus icon — reads more clearly as "add a folder context" vs the leading + in the tab strip (which adds a tab in the current folder).

Installation

  • Download Push-1.1.31.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.30

2026-04-16

Terminal tabs now feel like a full Mac-native app — drag to reorder, open any folder with one click, and typing just works the moment you switch tabs.

What's changed

Drag tabs to reorder

Grab any tab in the strip and drag it left or right to reorder — same gesture as Safari, Chrome, or Terminal.app. The new order persists across quit and relaunch.

Open a new terminal in any folder

A new button sits in the toolbar next to the folder chips. Click it, pick any folder from the native macOS file picker, and Push opens a new terminal tab there. The strip auto-filters to that folder so the new tab is grouped with any siblings.

The leading + in the tab strip still opens a new tab in the current folder — the toolbar's is specifically for jumping into a different folder.

Typing works immediately after tab switch

Switching between tabs used to require one extra click inside the terminal before keystrokes would land. Fixed — the moment you switch tabs, the new tab's cursor is live and ready to take input.

Cleaner tab strip

  • Safari-style hairline dividers between tabs, so the strip reads at a glance even with a lot of tabs open.
  • Folder-filter chips now show a small count of how many tabs are open in each folder, plus a total next to "All".
  • "Reopen closed" moved from the toolbar into the right edge of the tab strip, where it's visually scoped to the tabs themselves.

Installation

  • Download Push-1.1.30.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.29

2026-04-16

The terminal now renders in SF Mono — the same typeface as Apple Terminal — out of the box.

What's changed

Native Mac typeface in the terminal

Push's embedded terminal was falling back to a generic monospace font because SF Mono isn't a public macOS font — Apple Terminal uses a private variant that third-party apps can't see.

On first launch, Push now silently installs Apple's official SF Mono into ~/Library/Fonts/ and sets it as the default terminal typeface. The first time you open a terminal, it looks like Apple Terminal. No setup, no prompts, no config file to edit.

If you're offline on first launch the install just skips and Push uses a fallback font — no error, nothing breaks — and retries on the next launch.

Installation

  • Download Push-1.1.29.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.28

2026-04-16

⌘⇧T is now rock-solid — it brings back the tab you just closed, not a random Claude session from three days ago.

What's changed

Cleaner "Reopen Closed Tab" behavior

Reopening a closed tab (⌘⇧T or the toolbar's arrow button) was occasionally dropping users into a Claude session they didn't recognize. Root cause: the closed-tab history survived app restarts, and old entries could carry stale session pointers that no longer matched what the user thought they were undoing.

Now the undo history is scoped to the current launch — same as Cmd+Z in every other macOS app. Close a tab by accident, ⌘⇧T brings it back. Quit Push, and the stack is a clean slate on next launch.

What's unchanged: your live tabs still persist across quit+relaunch with their Claude sessions auto-resumed — that's the workspace-restoration promise and it stays exactly as it was.

Background cleanup of stale session pointers

On launch, Push now sweeps out leftover Claude session marker files from tabs that no longer exist (force-quit leftovers, historical iterations, etc.). Prevents those silent zombies from haunting any future session. Live tabs' markers are always preserved.

Installation

  • Download Push-1.1.28.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.27

2026-04-15

Auto-updates are quieter now, and the install prompt tells you your Claude session will be safe across the relaunch.

What's changed

Gentle background auto-updates

Background update checks now silently download the new version and surface Sparkle's native "Ready to install" alert without stealing focus from whatever terminal you're in. The loud, foreground download window that used to flash up every 30 minutes is gone.

Manual Check for Updates… (app menu) is unchanged — when you ask for it, Sparkle still speaks up loudly.

Peace-of-mind copy on the install prompt

Every release's notes now start with a banner that shows up right next to the Install and Relaunch button:

Your existing Claude Code session will be saved and resumed automatically after the relaunch — no work lost.

Same session-resume mechanism that 1.1.25 and 1.1.26 shipped — this just makes it visible at the moment the user is about to click Install.

Installation

  • Download Push-1.1.27.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.26

2026-04-15

Undo-close now replays the same auto-resume path as quit+relaunch.

What's changed

Reopen-closed-tab reuses the proven resume path

⌘⇧T (reopen last closed tab) used to run a parallel "marker ceremony" to bring back the tab's Claude session. Now it just unhides the tab — the bundled .zshenv sees the still-present session marker and fires claude --resume <sid>, exactly like on quit+relaunch. One code path for "restore tab + auto-resume", not two.

Also folded in:

  • Fixed a PUSH_CLAUDE_AUTO_RESUMED guard leak that could block a legitimate resume when Push-Dev was launched from an already-auto-resumed shell.

Installation

  • Download Push-1.1.26.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.25

2026-04-15

Claude tells you when it's done, and pasting an image from the clipboard works.

What's new

Tab badges for Claude "done" and "needs attention"

Every time Claude Code wants your attention — a turn completes, a permission prompt pops up, it's waiting on input — the tab the request came from lights up with an accent-dot badge, the Terminal row in the sidebar shows the aggregate count across tabs, and the Push Dock icon mirrors it when the app isn't frontmost. Switching to the tab clears all three.

Wired via Claude Code's own Notification / Stop / SubagentStop hooks — same pattern cmux uses, no polling, no ANSI sniffing.

Paste an image from the clipboard

Copy an image in Finder → ⌘V in Push → full path lands at the cursor and Claude renders the attachment inline. Same for screenshot-to-clipboard (⌘⇧5 → "Save to Clipboard") or copies from Preview — those get saved to a temp file and the path gets pasted. Previously, Finder-copied images dropped to the bare filename (no directory), and raw clipboard image data didn't paste at all.

Plain text paste is unchanged.

Installation

  • Download Push-1.1.25.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.24

2026-04-15

Hotfix: typing in plain shell tabs no longer eats the last letter.

What changed

Fixed: terminal typing regression

In v1.1.22 / 1.1.23, typing into a plain zsh tab (not inside Claude Code) caused every keystroke to appear as "selected" and the cursor would stay put — the last letter typed kept being replaced by the next. The tier-2 keyboard refactor had introduced macOS input-context routing for IME support, which leaked marked-text state onto normal typing in plain shells. Claude Code's TUI swallowed the stray escapes silently, which is why it only showed up in bare prompts.

Typing is back to the pre-v1.1.22 behavior (proven stable across 20+ releases). As a known trade-off, dead-key composition (Option+e → é) and IME preedit are disabled for now; they'll come back in a follow-up with a narrower gate.

Installation

  • Download Push-1.1.24.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.23

2026-04-15

Tabs now tell you when they want attention, paste lands where you're looking, and updates check every 30 minutes.

What's new

Tab notification badges

Every terminal tab now surfaces an unread counter when the shell or an embedded program signals attention. Claude Code's "task done" beep, any OSC 9 desktop notification, and nonzero shell-command exits all bump the badge on the tab that produced them — but only if you weren't looking at that tab when it happened.

The badge clears the moment you switch to the tab. A sum across all tabs is also mirrored onto the Dock icon, so when Push isn't frontmost you see a number on the app's Dock icon until you come back.

Paste lands in the active tab (fix)

Previously ⌘V always pasted into the first-created tab regardless of which tab was visible. AppKit's performKeyEquivalent walks the view hierarchy depth-first and the first pane consumed the shortcut. Fixed — only the active pane claims ⌘V / ⌘C / ⌘K now. Menu → Paste, right-click Paste, and drag-drop were already correct; this was exclusively a shortcut-routing bug.

Auto-update check every 30 minutes

The Sparkle check interval dropped from 24 hours to 30 minutes, so new releases reach you much faster. (If you're running an older version and reading this from the release notes page: you'll get the upgrade prompt the next time the check fires.)

Installation

  • Download Push-1.1.23.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.22

2026-04-15

Terminal feels instant. Click Terminal — every saved tab is already warm and resumed in the background. Open a new Claude session — no more 15-second wait.

What's new

Pre-warmed terminal sessions

Previously, the first click on the Terminal sidebar spun up every saved tab simultaneously — visible lag with 5+ tabs as PTYs, shells, and Claude resumes all started at once.

Now Push pre-creates each tab's surface in the background at app launch, staggered ~400 ms apart. By the time you click Terminal, every pane already has a live PTY, a running shell, and a resumed Claude session. The tab strip shows up; clicking a tab is instant.

Instant new Claude sessions

The claude command in a fresh Push tab used to take ~15 seconds before you could type — Push was running claude -p "" behind the scenes just to materialize a session file. That's gone.

Now we pass --session-id <push-tab-id> to Claude, which writes the session file naturally on your first real input. Net effect: same instant feel as a plain claude invocation, with our tab UUID still pinned for auto-resume across app quits.

Cmd+click URLs, right-click menus, drag-and-drop files

Catching up to what every other terminal does:

  • ⌘-hover any URL in terminal output to underline it; ⌘-click opens it in your default browser.
  • Right-click any tab for Copy / Paste / Clear.
  • Drag a file from Finder into a terminal — the path lands at your cursor, shell-escaped (so paths with spaces or apostrophes work without manual quoting).
  • First click on a non-frontmost Push window now lands in the terminal instead of being eaten by window activation.

International input

Dead keys, accent composition (Option+e → é), the emoji picker, and Japanese / Chinese / Korean IME composition all work in the Push terminal now via interpretKeyEvents + ghostty_surface_preedit wiring. ⌘V / ⌘C / ⌘K via performKeyEquivalent also fire reliably across tab switches and sidebar remounts.

Rename a terminal tab

Right-click any tab → Rename… opens a native macOS dialog. Type a name, hit return — that name now sticks even when the underlying shell tries to update its own title via OSC. Use Automatic Title in the same menu reverts to the live title. Renames persist across app restarts.

Toolbar polish

The terminal toolbar simplified to a single Resume last Claude button (the New-Claude and pu-work shortcuts were just shell commands you can already run inside any tab). The folder filter group is now a proper one-of-many selector with an All chip, padded to breathe inside the Tahoe glass capsule.

Installation

  • Download Push-1.1.22.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.21

2026-04-15

Undo-close for terminal tabs (⌘⇧T) and a new folder-filter row in the toolbar that lets you scope the tab strip to one project at a time.

What's new

⌘⇧T reopens the last closed tab

Works exactly like Chrome / Safari: close a tab by mistake, press ⌘⇧T, it comes back. The reopened tab keeps its original id, title, and working directory — and if it was running a Claude Code session, the session auto-resumes in the same transcript.

The undo stack is capped at 10 and persists across app quits, so a tab you closed yesterday can still be rescued today.

Folder filter chips in the toolbar

When you have several tabs spread across multiple projects, the toolbar now surfaces a chip per distinct folder — e.g. All · push-macos · push-website · product. Click a chip to narrow the tab strip to just that folder; click All to show everything again. Chips are derived from live tabs, so they appear and disappear as you cd around.

Cleaner toolbar

The New Claude here and pu work buttons are gone — both duplicated flows you can already trigger from inside any shell tab. What's left is one native Resume last Claude button plus the folder filter group. Less chrome, more room.

Faster, cleaner app quit

Every PTY is torn down explicitly on ⌘Q, so child processes never outlive the Push process and can't hold the server port open past shutdown.

Installation

  • Download Push-1.1.21.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

v1.1.20

2026-04-15

Terminal tabs and Claude Code sessions now survive ⌘Q. Quit Push, reopen, and your Claude conversations are exactly where you left them — same transcripts, same history, no clicking required.

What's new

Tab persistence + Claude session auto-resume

Every Push terminal tab is saved to disk and restored on app launch. If a tab was running a Claude Code session when you quit, it resumes that exact session — same conversation, same context, same working directory. No clicks, no manual --resume <id> typing.

How it works (roughly):

  • Each Push tab gets a stable UUID injected as PUSH_TAB_ID into its shell.
  • Our bundled zsh integration wraps claude so it always uses that UUID as the session id. Tab ↔ session is 1:1, deterministic.
  • Markers track the live session per tab. ⌘Q leaves the marker behind; on next launch each tab reads its marker and runs claude --resume <sid> automatically.

The architecture preserves any claude() function you already have in your ~/.zshrc (e.g. one that adds --dangerously-skip-permissions) — your flags pass through unchanged.

/resume from inside Claude is also tracked

Type /resume <some-old-uuid> inside Claude's TUI to switch to a different conversation, then quit Push — when you reopen, the tab restores into the switched-to session, not the original. Implemented via Claude Code's SessionStart hook, which fires deterministically on every session-start event including the slash command.

Cleaner shell experience

The shell-integration debug output is now opt-in via PUSH_DEBUG=1. By default, your terminal opens with nothing but a clean prompt. All transitions still get logged to ~/.push/mac/shell-debug.log for postmortem if anything misbehaves.

Smaller cosmetic improvements

  • The claude -p "" bootstrap no longer leaves a "ready / Ready." exchange at the top of every session's transcript. Resumed sessions open as if you'd just typed claude for the first time.

Installation

  • Download Push-1.1.20.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac
  • ~200 MB disk space

Known limitations

  • Auto-resume binds tabs to Claude sessions only when claude is launched through a Push tab's shell. If you run claude from a terminal outside Push (Terminal.app, iTerm2, etc.) and somehow expect Push to pick it up, that won't happen — Push only knows what its own tabs do.
  • claude --continue (Claude picks the most recent session globally) is passed through verbatim. Push doesn't bind that tab, so on restart you'd land in a fresh shell.
  • Bash users get a plain claude (no tab binding). The shell integration is zsh-only for now.

v1.1.19

2026-04-15

Two terminal fixes that should have shipped in 1.1.18: paste works everywhere, and Claude Code's voice input actually asks for microphone access now.

What's new

Paste + text injection

The Terminal section now implements the standard macOS text-input protocols it was missing:

  • Edit → Paste (menu bar) and ⌘V both reliably paste clipboard text. Previously only keybinding-path ⌘V worked, and the Edit menu was greyed out.
  • Wispr Flow and other text-injection tools (dictation, accessibility-based automation) can now deliver text into the terminal. They write through NSTextInputClient.insertText, which we didn't implement — text went nowhere.
  • Accessibility role is now .textArea, so AX-based tools see the terminal as a text target at all.

Claude Code voice input microphone access

Voice-input inside an embedded terminal (e.g. claude --voice) used to fail with "No audio detected from microphone" and macOS never showed a permission prompt.

Root cause: child processes spawned from Push inherit Push's sandbox. For macOS to prompt, the parent app (Push) needs NSMicrophoneUsageDescription in its Info.plist and com.apple.security.device.audio-input in its entitlements. Push had neither, so macOS silently denied with no UI.

1.1.19 adds both. On first use, macOS will prompt for mic access. The same plumbing covers any other TCC-gated capability (camera, etc.) we wire up later.

If you were silently denied before upgrading, macOS remembers that. Run this once in Terminal.app to reset:

tccutil reset Microphone ai.massless.push

Then relaunch Push. New installs don't need this.

Docs

  • New doc/TERMINAL.md — architecture reference for contributors touching the native terminal (surface manager, tab store, shell-integration injection, TCC inheritance, cmux parity gaps).

Installation

  • Download Push-1.1.19.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon Mac (1.1.16+ dropped Intel support)
  • ~200 MB disk space

CLI

No CLI changes. Latest @masslessai/push remains on npm at 0.4.2.

v1.1.18

2026-04-15

Push 1.1.18

v1.1.17

2026-04-15

First run now sets you up completely — no folder picker, no questions. And if you've been using Push since before 1.1.17, a new card in Settings lets you catch up in one click.

What's new

Onboarding: Push sets itself up

Previous versions got you to a working server and a workspace, but stopped short. You still had to figure out which folder your agent should watch, create a coder agent by hand, and invent a first task to test it on. Nobody knew what "pick a folder" meant in practice.

1.1.17 finishes the job. First run now:

  • Detects the project folder you've most recently been using Claude Code in (we read ~/.claude/projects/ and score by recency, git presence, and CLAUDE.md presence).
  • Creates a default agent named coder pointed at that folder, with heartbeat + wake-on-demand enabled and a $50/month budget.
  • Seeds a welcome issue assigned to coder so your first successful agent run is visible, not something you have to invent.
  • Wakes the agent on the welcome issue automatically — the first thing you see in the feed is Push doing work for you.

The step renders live: a checklist ticks off as each of the 10 phases completes. "Show terminal" reveals the raw log if you want to see what Push is doing under the hood.

Paused ≠ failed

If Push can't auto-detect a project folder (no Claude Code history, no ~/workspace), it now pauses cleanly with an amber "Try again" — instead of showing a scary red error. Same for any other step that's waiting on you or a missing prerequisite (~/.claude not installed, etc.). Failures are still red; prerequisites are amber.

Settings → "Coder agent" card

Users who upgraded from 1.1.16 or earlier never saw the new onboarding step because their hasCompletedOnboarding flag was already true. To close that gap, Settings → Integrations has a new Coder agent card with a "Run setup" button. Same script as onboarding, same checklist, in a modal sheet. Idempotent — if you already have a coder agent, it reuses it and skips the welcome seed.

pu setup on the CLI

The terminal equivalent works from any shell:

pu setup --json         # structured NDJSON events
pu setup --dry          # plan only, no mutations
pu setup --cwd <path>   # override folder detection
pu setup --force        # re-seed the welcome issue
pu setup --skip-wake    # skip the final agent wake

pu skill install is also new — standalone skill installer for users who prefer npm i -g @masslessai/push over Push.app.

Release pipeline fix

Fresh release bundles now include ghostty-shell-integration resources that were previously missing — the terminal's shell integration features (prompt markers, cwd reporting) work correctly on fresh installs.

Installation

  • Download Push-1.1.17.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update. Upgraders: open Settings → Coder agent → Run setup to provision the default agent if you don't have one.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon only (M1 or later)
  • ~300 MB disk space
  • Claude Code installed (used by the default coder agent)

v1.1.16

2026-04-15

The DMG is 79% smaller. Same app, same features — we just stopped shipping three things that shouldn't have been in the bundle.

What's new

Apple Silicon only, DMG 513 MB → ~130 MB

Every Push release from 1.0.0 through 1.1.15 shipped a universal binary with ~1.1 GB of dead weight. 1.1.16 cuts three compounding sources of bloat that we discovered while auditing the release pipeline:

  • Apple Silicon only. Every Mac sold since 2020 is arm64. Intel slices (the x86_64 Swift binary, the x86_64 Node runtime, and @embedded-postgres/darwin-x64) added ~440 MB installed with no user benefit — the Intel install base is in single digits and shrinking. Info.plist and the build pipeline now produce an arm64-only binary; Intel Macs will get a standard system "can't be opened on this Mac" dialog instead of a cryptic module-not-found crash at startup.
  • GhosttyKit.xcframework removed from the bundle. libghostty is linked statically into the Push binary at compile time (we confirmed with otool -L and nm — the _ghostty_* symbols live inside the Push executable). The 541 MB xcframework that was also being copied into Contents/Frameworks/ was pure dead weight at runtime, never loaded. We just stopped copying it.
  • Postgres dylib de-duplication. Our build was using rsync --copy-links, which dereferenced every symlink inside @embedded-postgres/darwin-arm64 — including intra-package version aliases like libicudata.dylib → libicudata.77.dylib → libicudata.77.1.dylib. That single 61 MB file was being shipped three times. Switching to --copy-unsafe-links preserves the real symlinks and saves ~170 MB installed without changing what actually loads at runtime.

Concrete numbers, measured end-to-end:

1.1.151.1.16
Installed1.4 GB294 MB
DMG download~513 MB~130 MB

Nothing else changes. Every feature — the native terminal from 1.1.15, embedded Postgres, the server, the UI — still works identically. We've just stopped asking users to download four extra copies of everything.

For Intel Mac users

1.1.15 was the last universal build. 1.1.16 will not install on Intel Macs. If you need Intel support, stay on 1.1.15 — your local data in ~/.push/ will continue to work with any future Intel-compatible release we choose to ship.

Installation

  • Download Push-1.1.16.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon only (M1 or later) — Intel Macs not supported starting with 1.1.16
  • ~300 MB disk space (was ~1.5 GB)

v1.1.15

2026-04-15

The Terminal section is now a real, native Mac terminal — multi-tab, GPU-rendered via libghostty, with cwd-inheritance on new tabs and a translucent macOS material background that adapts to dark/light mode.

What's new

Native multi-tab terminal

  • The Terminal sidebar entry now hosts as many concurrent shells as you want, each its own libghostty surface (the same engine that powers Ghostty.app).
  • Tabs persist across sidebar navigation. Switching to Issues / Agents and back keeps every PTY running — no more lost top, tail -f, or long-running shells.
  • + button at the leading edge (easier to hit than the trailing edge once you have many tabs).
  • Keyboard: ⌘T new tab, ⌘W close, ⌘⇧] / ⌘⇧[ cycle.
  • Tab titles update live from the terminal's own OSC 0/2 stream — Claude Code session renames flow straight onto the tab label.

Smart cwd inheritance on new tabs

  • Click + while you're in ~/code/foo and the new tab opens in ~/code/foo, not $HOME — same behavior as Terminal.app, iTerm2, and Ghostty.app.
  • Implemented by bundling Ghostty's shell-integration scripts into Push.app and injecting ZDOTDIR at surface creation, so spawned shells emit OSC 7 (cwd reports) regardless of your personal zsh setup.

Native macOS look

  • Terminal background is now an NSVisualEffectView with the system content material — adapts to dark/light mode and picks up window translucency, instead of the old hard-coded black slab.
  • Ghostty cells render with background-opacity = 0 so the system material shows through.
  • Terminal sidebar entry moved into the Overview group (after Feed) for faster reach.

Bug fixes

  • Arrow keys (and page-up/down, F-keys, Home/End, all macOS function-key codepoints) now produce the correct CSI escape sequences instead of garbled CJK glyphs. Caused by macOS's private-use-area function-key encoding being forwarded as raw text into the PTY.

Installation

  • Download Push-1.1.15.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

CLI

No CLI changes in this release. Latest @masslessai/push remains on npm at 0.4.2.

v1.1.14

2026-04-14

Session tracking rebuilt. Opening Claude Code from anywhere — plain claude, pu work, pu session — now reliably shows up as a session in the Mac app, tied to whatever issue you're on.

What's new

Claude Code session tracking actually works now

Previous versions documented a /pu <issue> lifecycle that depended on an env var Claude Code doesn't set (CLAUDE_SESSION_ID) and hook registrations that get overridden by terminal wrappers like cmux. In practice, interactive sessions were invisible to Push. The 1.1.14 rebuild moves the contract onto the pu CLI itself, which nothing wraps or replaces:

  • New commands: pu session begin --issue <n>, pu session end, pu session current.
  • The CLI auto-injects X-Push-Run-Id on every mutation from a per-session sidecar. You don't manage headers.
  • pu session (the launcher) auto-creates a freestanding run before spawning Claude Code, so every launch is visible in Push from t=0.
  • The /pu skill has been simplified from a 50-line six-step procedure to a two-command contract.
  • Server-side sweeper: interactive runs idle for over an hour are now finalized as detached (was: failed at four hours), with the issue's active-run lock released automatically.

Full design details in doc/SESSION-TRACKING.md.

Graceful UX when Push.app isn't running

  • pu CLI now detects connection failures and prints a clear "Push server isn't running — Start it with: pu server start" instead of a raw TypeError: fetch failed.
  • pu server start on macOS launches Push.app via open -a Push and polls /api/health until ready, instead of spawning a competing headless Node server. One server, one lifecycle.
  • /pu slash command auto-recovers once per session: if Push isn't running, it starts the app, tells you in one line, and retries your command.
  • Push.app now gives the Node server a stdio lifeline so that an app hard-crash can't orphan the server — the Node process sees EOF on stdin and exits cleanly.

UI

  • Inspector replaced with a dedicated sidebar + push-navigation pattern.

Installation

  • Download Push-1.1.14.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

CLI

The @masslessai/push CLI ships separately on npm at 0.4.2. Update with npm install -g @masslessai/push to pick up the new pu session command family and the server-down UX improvements.

v1.1.13

2026-04-14

Fixes auto-update. Every prior release, going back to 1.0.0, has been silently invisible to Sparkle.

What's new

  • Sparkle auto-update works. The appcast generator had been writing the marketing version ("1.1.12") into <sparkle:version>, but Sparkle's default comparator uses that element as the build number and splits it on dots. It compared installed CFBundleVersion=10 against feed "1.1.12" as [10] vs [1,1,12], saw 10 > 1 at the first index, and concluded the installed app was newer than the feed — hence "You're up to date!" on every auto-update check since 1.0.0. Fixed: <sparkle:version> now carries CFBundleVersion (a strictly-increasing integer), <sparkle:shortVersionString> carries the marketing version. The preflight monotonicity check was reading the wrong xpath; that's fixed too, so it will actually catch this class of regression going forward.

For existing users — important

If you are running any build between 1.0.0 and 1.1.12, auto-update cannot rescue you. Your Sparkle client will keep saying "You're up to date" forever because the comparison bug is in the feed it's reading. You need to install 1.1.13 once by hand. After that, auto-update will start working and 1.1.14 onwards will arrive silently the way it's supposed to.

Installation

  • Download Push-1.1.13.dmg from releases.pushto.do.
  • Drag Push.app to /Applications, replacing the existing copy.
  • Open it.

Your local data in ~/.push/ is preserved across the update.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.12

2026-04-14

Release pipeline fully green end-to-end — no user-facing app changes since 1.1.11.

What's new

  • Post-publish CI smoke passes again. Every release since 1.1.8 had been reporting red CI because the smoke script launched Push.app from /tmp, where macOS AppMover shows a blocking "Move to Applications" modal. On a headless CI runner there is no user to click, the modal hangs indefinitely, and the server never starts. Fixed: the smoke now copies Push.app to /Applications before launch, matching AppMover's Bundle.main.isInstalled short-circuit. Confirmed via a disposable debug-smoke workflow against the live 1.1.11 DMG. Side effect: the website-deploy trigger fires again, so pushto.do stays in sync with each release instead of lagging until ISR revalidation.

For users

Nothing to do. If you're on 1.1.10 or 1.1.11 you already have the macOS 26.2 Tahoe launch-crash fix; 1.1.12 is the same app with a green release pipeline.

Installation

  • Download Push-1.1.12.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.11

2026-04-14

Release pipeline reliability — no app changes since 1.1.10.

What's new

  • CI smoke test now polls the real health endpoint. The post-publish smoke that was added in 1.1.8 had always asked the server for /health — an endpoint the server has never exposed (it lives at /api/health). Every release since 1.1.8 failed CI at that step, which meant the automatic website-deploy trigger was skipped and the pushto.do download button lagged behind the real appcast by up to 10 minutes. Fixed: smoke hits the right URL, finishes in ~3 seconds, CI is green, and the website picks up each new release automatically.

For users

Nothing to do. If you're on 1.1.10 you already have the macOS 26.2 Tahoe launch-crash fix; 1.1.11 is the same app with working release infrastructure.

Installation

  • Download Push-1.1.11.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.10

2026-04-14

Critical fix for a launch crash on macOS 26.2 Tahoe.

What's new

  • Fixed a fresh-install launch crash on macOS 26.2. On Tahoe 26.2 (SwiftUI 7.2.5), a handful of users hit an NSInternalInconsistencyException from NSToolbar seconds after launching — the window would appear, then the app would die before anything became interactive. Root cause: SwiftUI's new incremental-insert path for toolbar items throws on identifier collisions that older SwiftUI silently deduped. Every toolbar item in Push now carries an explicit, namespaced identifier, so the collision is impossible regardless of SwiftUI version.
  • Release pipeline smoke-test timeout bumped 30s → 120s. Post-publish health check was failing on slower CI runners even when the actual artifact was fine (this is why 1.1.9 showed as "failed" in CI even though the DMG shipped correctly).

Installation

  • Download Push-1.1.10.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.9

2026-04-14

Every session now tells you which issue it's working on — and /pu inside Claude Code finally shows up on the dashboard.

What's new

Sessions know about their issue

The sessions list and session detail view used to show "interactive · slash_pu" with no hint of which issue the agent was actually working on. Now every session — timer-tick, user-spawned, proactive, or interactive /pu — surfaces its linked issue: the identifier chip (e.g. MAS-3387), the title, and its status. Click through from the detail view straight to the issue page.

No backfill needed. Old sessions already had the issue reference in their context snapshot; Push just wasn't rendering it. The moment this update installs, your entire session history lights up with the right context.

/pu <issue> in Claude Code is first-class

When you run /pu 3387 inside a Claude Code session, Push now:

  • Claims the issue as actively executing (atomic, race-safe — two concurrent /pu invocations can't clobber each other).
  • Captures the Claude Code session UUID on the run for resume-ready metadata.
  • Releases the lock cleanly when the session ends, whether you finalize explicitly or just close the window (in which case the run is marked detached rather than leaking as running forever).

Approval and human-in-the-loop flows are unchanged: closing the heartbeat run doesn't close the issue, so pending approvals still route through the normal path.

Release pipeline reliability

CI post-publish smoke would occasionally reject freshly-published DMGs with "Unnotarized Developer ID" even though the Push.app inside was correctly notarized and stapled. Fixed: the DMG envelope itself now gets notarized + stapled, so verification works offline and doesn't depend on Apple's notary service being responsive at the exact moment CI polls.

Installation

  • Download Push-1.1.9.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.8

2026-04-14

/pu sessions inside Claude Code now show up as live work on the issue.

What's new

  • Interactive /pu <issue> is first-class. When you run /pu 3387 inside a Claude Code session, Push now claims the issue as actively executing, attaches the Claude Code session UUID to the run, and releases the lock cleanly when the session ends. The issue card surfaces the session while it's active — same visual affordance you get for spawned runs, minus the live log (the subprocess isn't owned by Push, so stdout isn't streamed).
  • No more zombie interactive runs. If you close the Claude Code window without explicitly wrapping up, session-end finalizes the run as detached and frees the issue lock. Previously the run stayed running forever and the issue stayed locked.
  • Resume-ready session metadata. The Claude Code session UUID is now stored on the heartbeat run itself (sessionIdAfter), visible on the session detail page with a copy button. Paves the way for one-click resume into the exact Claude session from Push.

Under the hood

  • Interactive run create atomically claims issues.executionRunId only when the issue is free (race-safe; two concurrent /pu invocations don't clobber each other).
  • New detached run status — distinct from succeeded so dashboards can tell an explicit handoff from a window-closed-mid-work.
  • Approval / HITL flow is unchanged: closing the heartbeat run does not close the issue, so pending approvals still route correctly.

Installation

  • Download Push-1.1.8.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.7

2026-04-14

Push 1.1.7

v1.1.6

2026-04-14

Push 1.1.6

v1.1.5

2026-04-14

Push 1.1.5

v1.1.4

2026-04-14

Push 1.1.4

v1.1.3

2026-04-14

Push 1.1.3

v1.1.2

2026-04-14

Push 1.1.2

v1.1.1

2026-04-14

Push in your Dock, a complete install, and download links that never go stale.

What's new

  • Push now lives in your Dock. Alongside the menu bar. You can quit Push from the Dock like any other Mac app, it shows up in ⌘-Tab, and Force Quit sees it by name. The menu-bar icon is still there as the server-status heartbeat and quick-access point — it's just no longer the only signal that Push is running.
  • Database ships correctly. Some embedded database binaries were missing from the v1.1.0 DMG, which could cause workspaces to fail to start cleanly on a fresh install. v1.1.1 bundles them properly.
  • Download links never go stale. The website and auto-update now always point at immutable versioned URLs. If a future release ever fails to publish, you'll simply keep using the prior working version automatically — no 404s, no stale bytes, no manual fixes.

Installation

  • Download Push-1.1.1.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.1.0

2026-04-13

A friendlier install, a calmer first launch, a cleaner way out.

What's new

  • Redesigned installer. The Push DMG now matches Push for iOS — same warm off-white canvas, the same subtle grid, a single hero arrow guiding you from Push.app to Applications.
  • No more "running from Downloads" confusion. If you launch Push from your Downloads folder or the DMG, it offers to relocate itself to Applications so the CLI, Claude skills, and Login Item all work reliably. (Under the hood: App Translocation handled via AppMover.)
  • Context before every permission prompt. Every install-time ask — your password, notifications, Login Item access — is now preceded by a short explanation of what's about to happen and why.
  • New "You're all set" screen. After onboarding, Push points you at its menu-bar icon with a gentle pulse (it's easy to lose track of a menu-bar-only app) and offers one-click actions to try your first task or install the iPhone companion.
  • Settings → Uninstall Push. One place to cleanly remove everything Push installed — CLI symlink, Launch Item, app data, and optionally the Claude skills. A good-citizen way to leave.

Installation

  • Download Push-1.1.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it — the new onboarding walks you through setup.

Existing users will be offered this update automatically via Sparkle.

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

v1.0.1

2026-04-13

Fix launch crash affecting all v1.0.0 installs.

  • v1.0.0 shipped without the Sparkle auto-update framework embedded in the app bundle. Every launch failed immediately with a dyld library-not-loaded error. v1.0.1 embeds the framework correctly and adds the required runtime rpath so the app starts successfully.
  • No changes to features or data — if you installed v1.0.0 and it bounced on launch, installing v1.0.1 will fix it.

v1.0.0

2026-04-13

First public release.

What's new

  • Native macOS app. Drag-and-drop install via DMG. No Node, no Docker, no terminal required to get started.
  • Ghostty terminal built in. Native GPU-accelerated terminal for running agents — bundled, universal (arm64 + x86_64), no separate install.
  • Claude Code integration. First-launch wizard offers to install the pu CLI + /pu slash-command skill to ~/.claude/skills/pu/.
  • Auto-update. Sparkle keeps you on the latest stable silently.
  • Relay-ready. Connects to the hosted relay so your iPhone can reach your Mac.

Installation

  • Download Push-1.0.0.dmg from releases.pushto.do.
  • Drag Push.app to /Applications.
  • Open it — first launch walks you through setup (local server, CLI install, Claude skills, Apple Sign-In for iOS pairing).

System requirements

  • macOS 14 Sonoma or newer
  • Apple Silicon or Intel Mac (universal binary)
  • ~200 MB disk space

Known limitations

  • iOS companion app is TestFlight-only for 1.0; App Store release is coming.
  • Lab UI and web-based terminal fallback are dev-only and not included in this build.

Credits

Forked from paperclipai/paperclip. Terminal rendering powered by Ghostty. Auto-update by Sparkle.