Skip to content

Desktop

The Shipper desktop app is a supported macOS app for running the Shipper issue lifecycle from a visual pipeline board. It uses the same core engine as the CLI and covers the same workflow stages: issue intake, grooming, design, planning, implementation, PR review, remediation, and merge readiness.

Desktop does not create a separate project database. Workflow state lives in GitHub labels, issue comments, PRs, and Shipper artifacts, and local settings use the same Shipper conventions as the CLI. You can switch between desktop and CLI work on the same repository because both entry points read and write the same state.

Use desktop when you want visual triage, queue monitoring, interactive grooming, setup terminal sessions, pause/resume controls, action queues, logs, and hands-on operation from one board.

Use the CLI when you want scripts, CI or container execution, direct terminal commands, explicit stage invocation, or headless automation around commands such as shipper next, shipper ship, shipper merge, and shipper reset.

Many teams use both: desktop for day-to-day monitoring and control, CLI for repeatable commands and automation.

Download the latest macOS arm64 DMG or zip artifact from GitHub Releases. The current desktop artifacts are unsigned and not code-signed, so macOS may require manual confirmation before first launch.

Windows and Linux builds are not currently distributed. The workflow itself is GitHub-only today.

The app runs Shipper workflows locally, so the normal local prerequisites still apply:

  • Git and a GitHub-hosted repository.
  • GitHub CLI installed and authenticated with gh auth login.
  • Node.js and the configured coding agent CLI for stages that invoke an agent.
  • Repository Shipper settings that select the agent and command behavior.
  1. Install and authenticate GitHub CLI:

    Terminal window
    gh auth login
  2. Launch Shipper desktop.

  3. Resolve any prerequisite warning shown by the app, such as a missing GitHub CLI authentication session.

  4. Add or select a repository in owner/repo format from the repo picker.

  5. If the repository is not initialized, run setup/init when prompted. This creates or updates local .shipper/ configuration and ensures the GitHub workflow labels exist.

  6. Confirm the pipeline board loads issues from the selected repository.

After the board loads, desktop and CLI commands can operate on the same repository interchangeably.

After the first board load, desktop becomes an operating surface for the same issue lifecycle the CLI reference describes. The sections below cover the background queue, logs, terminal sessions, pause state, card actions, shared locks, automation toggles, and reset flow that power users need during day-to-day work.

The New Issue modal accepts a text request for the selected repository. When that repository’s configured agent supports image attachments, you can paste images into the dialog or use the attach image control to choose screenshots from disk.

If the configured agent does not support image attachments, desktop shows the unavailable attachment message in the modal and keeps New Issue text-only for that repository.

The desktop adoption modal lists open untracked issues and eligible open pull requests from the selected repository. Candidate rows are marked as Issue or PR so you can distinguish work that starts from an issue from work that adopts an existing pull request for review.

Eligible PR rows are open, non-draft, same-repository pull requests without shipper:* labels. PRs that reference multiple open same-repository closing issues, or whose single backing issue is already tracked by Shipper, remain visible but disabled with a reason. Draft PRs, fork or cross-repository PRs, closed or merged PRs, and PRs that already carry a shipper:* label are hidden from the list.

Adopt All Issues remains issue-only and never adopts pull requests. Use a PR row’s individual Adopt action, or the manual field, to adopt a pull request. The manual field continues to accept an issue or PR number or URL.

The action queue drawer shows desktop background commands launched by the board:

  • New for shipper new issue creation.
  • Ship for shipper ship stage advancement.
  • Init for shipper init repository setup.
  • Unblock for shipper unblock recovery checks.

Each queue row shows the command title, the New, Ship, Init, or Unblock badge, the repository, the latest output or detail line, and a relative timestamp. The timestamp affordance exposes the absolute time. Ship rows also show the workflow stage when the board has one cached for that issue.

Queue rows use these rendered statuses:

  • Queued: the command is waiting to start.
  • Running: the command is currently executing.
  • Succeeded: the command finished successfully. This is the user-visible success label even though the internal background status is still named complete.
  • Failed: the command exited unsuccessfully.
  • Paused: a ship command exited through the pause path.
  • Cancelled: the user explicitly stopped an item, so the row is shown as cancelled instead of a normal failure.

Queue history is only for the current desktop session. Running and queued rows live in memory in the desktop process, and visible rows live in renderer state. Finished rows stay visible until they are dismissed, removed with Clear finished, or cleared by restarting the app. Restarting desktop does not restore visible queue history.

Rows expose actions based on their current state. Logs opens command output when the row has logs available. The stop control cancels a queued or running row. The dismiss control removes finished Succeeded, Failed, Paused, or Cancelled rows. Clear finished removes every non-active row and leaves Queued and Running rows in the drawer.

Only one Ship command runs per repository at a time. If another ship starts for the same repository, it stays Queued and starts automatically when the active ship for that repository finishes. Ships for different repositories are not serialized by this rule.

Use Logs from an eligible queue row to open the background log viewer. Queued rows generally have no log content until they start running. Running commands stream output into the viewer as it arrives. Finished commands show the buffered output retained for that row. New rows use the same viewer after the desktop can load their JSONL log file.

The viewer follows the tail while you are scrolled to the bottom. If you scroll up to inspect earlier output, it stops auto-following and shows Jump to latest; selecting that control returns to the tail and resumes following new output.

Use Copy logs to clipboard to copy the visible log content. The copy control is disabled when the viewer has no log content and changes to a success icon after the clipboard write succeeds.

Groom opens an interactive shipper groom --mode interactive terminal session for the selected issue. Setup opens an interactive setup session for repository configuration. If you select Groom or Setup again while a live session for the same issue or repository already exists, desktop focuses the existing session instead of launching a duplicate.

The terminal drawer shows one tab per session. Groom tabs are labeled with the issue number, setup tabs are labeled with the repository, and each tab includes a status dot. The observed session states are:

  • running: the session has recent output or input activity.
  • waiting: no output has arrived for a short period, so the session may need attention.
  • finalizing: desktop has asked the session to finish gracefully.
  • exited: the process has ended and the tab can be dismissed.

Closing a terminal tab depends on that state. An exited session dismisses immediately. A finalizable running session is asked to finish gracefully and moves to finalizing. A running groom session with no result.json prompts Discard terminal progress? because closing it will terminate the agent and discard progress. A finalizing session prompts Force-kill finalizing session?.

Force-killing a groom session discards in-progress grooming work. After the process is killed, desktop attempts to unlock the issue and refreshes the active repository if that issue belongs to the repo you are viewing.

Pause is scoped to one issue within one repository and is saved in desktop pause state, so it persists across desktop restarts.

Pause behavior depends on what the issue is doing when you select it:

  • Running ship: desktop asks the active ship to halt at the next safe stage boundary, shows pending pause feedback, and records the issue as paused only after the command exits with the pause outcome.
  • Queued ship: desktop removes the queued ship session and immediately records the issue as paused. If the queued item has already raced into Running, desktop follows the running-ship pause path instead.
  • Idle issue: desktop records the issue as paused immediately without starting a background command.

There is one final-stage exception. If a running ship is already at shipper:pr-reviewed, Pause does not request a safe-boundary halt; desktop tells you to use Stop if you need an abrupt halt.

A paused card shows a paused indicator and a Resume action. Pause alone does not disable normal actions: Ship on a paused shippable card opens the Resume and ship confirmation, and Groom remains available on cards where Groom is normally rendered. Resume clears the desktop pause state and returns the issue to the standard ship and groom flows.

Issue cards expose primary buttons and an ellipsis menu. Availability depends on the card’s current labels, shipping state, and repository prerequisites.

| Action | Where it appears | Available when | Effect | | ---------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | | Groom | Primary button on New attention cards | The card is not blocked, locked, failed, or actively shipping; fetch prerequisites are satisfied; and a groom launch is not already pending. Pause alone does not disable Groom where it is normally rendered. | Opens or focuses the interactive grooming terminal for that issue. | | Ship | Primary button on non-ready pipeline cards | A repository is active, fetch prerequisites are satisfied, the card is not blocked, locked, failed, or actively shipping, and a ship launch is not already pending. Pause alone does not disable Ship. | Starts the next eligible background Ship command. On a paused card, opens the Resume and ship confirmation before starting. | | Stop Ship | Stop control beside a currently shipping card | A Ship row for that issue is Queued or Running. | Cancels the queued or running background command for that issue. | | Pause | Ellipsis menu | The card is not already paused. | Records desktop pause state immediately for idle issues, removes queued ships before pausing, or asks a running ship to pause at a safe stage boundary. | | Resume | Ellipsis menu | The card is paused. | Clears desktop pause state for that issue. | | Reset | Ellipsis menu, and the failed-card reset control | Backward reset targets exist and the issue is not currently shipping. Targets are New, Groomed, Designed, Planned, and Implemented when those are earlier than the current stage or valid for a failed/post-implementation issue. A non-stale shipper:locked label makes the preview unavailable. | Opens Reset Issue for the selected target. The reset is preview first, execute second. | | Priority | Ellipsis menu | The card menu can be opened. | Sets priority to High, Normal, or Low by adding or removing shipper:priority-high and shipper:priority-low. | | Unlock | Ellipsis menu | The card has shipper:locked, an unlock handler is available, and the issue is not currently shipping. | Clears a stale lock directly. Active locks prompt for confirmation before removing shipper:locked. | | Unblock | Ellipsis menu | The card has shipper:blocked, is not locked, and is not currently shipping. | Starts a background shipper unblock command. | | Close as not planned | Ellipsis menu | The issue is not locked and is not currently shipping. | Prompts for confirmation, closes the GitHub issue as not planned, and removes Shipper labels. |

Desktop and CLI clients coordinate through the same GitHub issue label: shipper:locked. There is no cross-machine messaging, presence channel, machine ID, or shared per-lock metadata. If two machines view the same repository, they both see the same label-backed lock state.

When a client starts protected work, it adds shipper:locked. The active lock holder refreshes the lock on a heartbeat by renewing the label event. Other clients judge staleness from the most recent shipper:locked label event in the issue timeline and the configured lock timeout. If that event is older than the timeout, the next client that touches the issue can clear the stale lock automatically before proceeding.

If a second client finds a non-stale lock, it treats the issue as locked and avoids conflicting work. Manual Unlock is appropriate when the process that held the lock is no longer running, such as after a crash on another machine, and you want to take over before automatic stale-clear occurs.

Auto-ship and Auto-merge are per-repository toolbar toggles on the pipeline board.

Auto-merge is saved in desktop app config per repository. Select the toggle to enable it for the active repository; select it again to disable it. When enabled for the selected repository, desktop passes merge behavior into Ship commands so ready PRs can enter the merge flow.

Auto-ship is enabled per repository for the current desktop session. Select the toggle to enable it for the active repository; select it again to disable it. After a ship finishes, desktop looks for the next eligible issue in that repository and starts it automatically. Auto-ship skips issues that are already active, paused, blocked, or failed.

Auto-ship also has a safety stop. After three consecutive non-retriable failures in one repository, desktop disables auto-ship for that repository and reports that auto-ship paused so you can investigate before more work starts.

Reset is a two-phase flow. It is not a one-click destructive menu action.

Phase 1 is preview. Selecting a backward target opens Reset Issue and scans what will be cleaned up: the target stage, labels to remove, pull requests to close, remote branches to delete, local branches to delete, worktrees to remove, and issue comment count. Preview can fail before showing a summary if the issue is closed, the issue has a non-stale shipper:locked label, the target is the current stage, or the target is ahead of the current stage.

Phase 2 is execute. Pressing Reset repeats validation, acquires the issue lock, runs cleanup, posts the reset notice, and releases the lock.

Reset only works backward and only on open issues. The Reset action is hidden while the issue is currently shipping, and both preview and execute refuse non-stale locked issues.

The desktop app does not currently provide these capabilities:

  • Application-level keyboard shortcuts for issue-card actions.
  • Right-click issue-card context menus.
  • Queue persistence across app restarts.
  • Changing paused issues so they hide Ship or Groom; paused cards keep normal actions as described above.

Shipper stores durable state in GitHub:

  • Workflow labels such as shipper:new, shipper:planned, shipper:pr-reviewed, and shipper:ready.
  • Control labels such as shipper:blocked, shipper:locked, and shipper:failed.
  • Priority labels used by auto-ship ordering.
  • Issue bodies and comments containing grooming, design, plan, implementation, review, and summary artifacts.
  • Pull requests and CI checks used by the review, remediation, and merge stages.

Desktop also has local state. Pause state is saved by the desktop app per repository and issue. Action queue rows are current-session memory and are not restored after restart. Local stage output, terminal sessions, and settings follow the same Shipper conventions the CLI uses. Desktop is a UI and process launcher over that shared model.

  • Desktop distribution is macOS arm64-only today.
  • Release artifacts are unsigned and not code-signed today.
  • Windows and Linux desktop artifacts are not currently provided.
  • Shipper workflows require GitHub-hosted repositories.
  • Release tags, package publishes, and desktop release uploads are maintainer-owned release tasks, not actions performed by the desktop app.