Everything waiting on your review, in the order you were asked.

Mrow is a small desktop app for the pull and merge requests where you’re the reviewer. It reads GitLab through glab and GitHub through gh, shows every diff natively, and keeps quiet until someone asks for you.

Install MrowSource on GitHubFree, for macOS 15 and later on Apple silicon, and Linux.
Mrow3
GHacme/web#482

Keep the filter when switching tabs

Lena Fischer wants to merge lena/sticky-filter into main

src/issues/IssueList.tsx+1 −1
2222export function IssueList({ tab }: Props) {
23 const [query, setQuery] = useState('')
23 const [query, setQuery] = useSearchParam('q')

Lena Fischer 10:02

Same hook the settings page uses.

You 10:20

Nice, does it debounce the URL writes?

2424 const issues = useIssues(tab, query)
2525 return <List items={issues} />

Try it: switch accounts, lists and rows, or move with j and k. Every person and repository in it is made up.

Sorted by when you were asked

Most review lists sort by when a request was opened or last touched. Mrow sorts by the moment you were asked to look. When someone asks again after pushing fixes, the request comes back to the top of Today.

The queue falls into Today, Yesterday, This week, This month and Older. Anything that has waited on you for more than two days shows its age in clay, so the old ones don’t hide under the new.

Tuesday, 4:10 pm

Today

Retry webhook delivery with backoffnorthwind/billing!305Asked 4:02

This week

Move preview environments to the shared runner poolnorthwind/infra!97Asked Monday

Thursday, 9:40 am, after Sam pushes fixes

Today

Retry webhook delivery with backoffnorthwind/billing!305Re-requested 9:40

This week

Move preview environments to the shared runner poolnorthwind/infra!973d
To review
You haven’t reviewed it yet, you’ve started, or new commits reset your review.
Reviewed
You approved, commented or asked for changes, and it’s still open.
Done
Merged or closed in the last 14 days. The window is yours to change.

The whole review, without the browser

The description renders the way its author wrote it. Every file’s diff has line numbers and syntax highlighting, and comment threads sit on the lines they’re about.

Comment on a line or on the whole request, tick files off as viewed while you go, and approve when you’re satisfied. Keep a few open in tabs and move between them.

Keep the filter when switching tabsApprove
src/issues/IssueList.tsx+1 −1
2222export function IssueList({ tab }: Props) {
23 const [query, setQuery] = useState('')
23 const [query, setQuery] = useSearchParam('q')

Lena Fischer 10:02

Same hook the settings page uses.

You 10:20

Nice, does it debounce the URL writes?

2424 const issues = useIssues(tab, query)
2525 return <List items={issues} />

GitLab and GitHub, one picker

Mrow reads GitLab through the glab command-line tool and GitHub through gh. Signed in to both? The picker at the top of the sidebar flips between them, the way you’d switch teams in a chat app.

Each account keeps its own queue, its own unread dots and its own three lists.

  • GLMerge requests, through glab
  • GHPull requests, through gh

Ask Cursor about the change

Press ⌘L and a chat opens beside the review, run by Cursor’s agent acp. Your first question carries the description, the diff and the threads, and the agent can read your local clone as it’s checked out. Ask where else a function is called, or what a change might break.

It’s read-only three ways. Chats run in Cursor’s ask mode, Mrow offers the agent no file or terminal access, and it declines every permission request, showing each one in the chat. You get one chat per request, kept across relaunches.

Ask CursorRead-only

Given the description, the diff of src/issues/IssueList.tsx and its threads.

Is anything else calling this the old way?

Two callers still expect the old behaviour. Both are in tests, so nothing in production changes, but they'll need updating before this merges.

// fixtures/IssueList.tsx, line 12

Talks to nothing but glab and gh

Mrow has no server, no sign-up and no analytics. Every request goes through the glab and gh tools you already use, and their tokens stay in your keychain, where those tools put them. Mrow never sees a token. All it keeps is a few preferences.

The only exception is the one you choose. Open Ask Cursor, and your question goes to Cursor through its agent, along with the review it’s about.

Every action has a key

You can work through a whole morning’s reviews without touching the trackpad.

Keyboard shortcuts
KeysAction
⌘1⌘2⌘3To review, Reviewed, Done
⌥⌘1⌥⌘2⌥⌘3Overview, Changes, Discussion
↑↓jkMove through the list
⌥⌘]⌥⌘[Next or previous request
⌘K⌘FFilter the list
⌘RRefresh
⌘O↩Open in the browser
⇧⌘AApprove
⇧⌘CCopy link
⌘↩Post the comment
⌃⌘SShow or hide the sidebar
⌘LAsk Cursor: open the chat, move into it, or close it
⇧⌘L⌥⌘LNew chat, choose the model
←→Change the model’s effort, in the model picker
escStop the answer, in the chat

Install it

One command downloads the latest release, checks it against the release’s checksum and installs it.

  • macOS 15 or later on Apple silicon, or Linux (x86_64 or arm64) with a Vulkan driver
  • glab signed in for GitLab, gh for GitHub, or both
Terminal
curl -fsSL https://mrow.wania.app/install | bash

On a Mac it puts Mrow in ~/Applications and opens it. On Linux it installs mrow and its desktop entry into ~/.local. Then sign in with glab auth login, gh auth login, or both.

Or download it

The latest release. Older ones, and what changed in each, are on the releases page.

Or build it yourself

Terminal
  1. git clone https://github.com/ZainW/mrow.git
  2. cd mrow/apps/desktop
  3. scripts/install.sh

Needs a Rust toolchain (rustup); on Linux, also libxkbcommon-dev and libwayland-dev, and run scripts/package-linux.sh --install instead. Builds from source don’t update themselves.