Skip to main content
CODEMUXManual

Pull & Merge Requests

Create, read, review, and merge pull requests on GitHub and merge requests on GitLab without leaving Codemux.

The Review pane in the right panel follows the change request for the branch you're on — its description, checks, comments, and diff — and lets you review and merge it in place.

Codemux supports GitHub and GitLab. It never stores hosting credentials of its own — each product is driven through its own command-line tool, using the credentials that tool already holds.

For the review workflow itself — leaving a verdict, line notes, replying to threads, and merging — see Reviewing & Merging. For the triage list across every repo you have open, see The Pull Requests Page.

Requirements

HostCLISign in with
GitHubghgh auth login
GitLabglabglab auth login

Check both from Settings → Source Control, which shows whether each CLI is installed, which account it's signed in as, and the exact command to fix it if not.

Bitbucket and Azure DevOps are recognized but have no integration; a checkout on one is named, marked read-only, and offered an Open in browser button.

Host Detection

Codemux works out which product a checkout talks to by reading its git remotes — no network call, no CLI, no auth. It prefers the remote your branch tracks, then origin, then the first one listed.

  • github.com and gitlab.com (including their SSH aliases) are matched exactly.
  • Any hostname containing github or gitlab is classified as that product — so self-hosted gitlab.acme.com and GitHub Enterprise on github.acme.internal both work with no configuration.
  • A neutral domain like git.acme.internal can't be guessed. Map it once under Settings → Source Control → Self-hosted servers; that mapping wins over everything else and syncs across your devices.
  • Anything unclassified is a normal state, not an error — the Review pane simply reports that the checkout isn't a supported repository.

Detection results are cached briefly, but failures aren't, so adding a remote or a host mapping takes effect immediately.

Terminology

Codemux follows the host's own vocabulary. On GitLab the Review pane reads Merge Request, the create button is Create MR, and references render as !12; on GitHub they read Pull Request, Create PR, and #172. Issue references stay # on both.

What Works Per Host

Every action is drawn from a capability the host declares, so a button you can see is a button that works. An operation a host doesn't declare is not drawn at all rather than shown and disabled.

GitHubGitLab
List, view, create change requestsYesYes
CI checksYesYes (pipeline jobs)
IssuesYesYes
Read review threads and inline commentsYesYes
Reply to a review threadYesYes
Resolve / unresolve a threadYesDiff discussions only
ApproveYesYes
Request changesYesNo — GitLab has no such verdict
Line-level review notesYesNo — the Code tab is read-only
Merge (squash / merge / rebase)YesYes
Draft ↔ ready, close, reopenYesYes
TimelineYesYes
Check out a request into a worktreeYesYes
Deployment previewsYesNo
Outdated thread labelsYesNo

If a backend call is attempted for an undeclared operation it refuses in plain language — "GitLab does not declare this operation — Codemux cannot resolve threads here. Open it in the browser instead."

Where To Open It

  • Right panel — click the Review pane in the pane deck. Its tab badges the comment count plus a rollup glyph for the checks: spinner, green check, or red ✕.
  • Pull Requests page — the sidebar footer's pull-request icon, or the command palette. See The Pull Requests Page.
  • Sidebar PR chip — every workspace with a request shows a chip like #372 on its sidebar row, colored by state; clicking it opens that request. A workspace with several requests reads #372 +8. When every request in the set builds on another one in it (one's base branch is another's head), the chip's icon becomes a stack icon, the workspace hover card heads the list Stack of 9, and a thin line joins the stacked requests — standalone requests in the same workspace stay unjoined.
  • Agent Chat Context Row — a clickable chip, colored by state.

Requests opened from a side branch

An agent that runs git checkout -b side-branch, commits, pushes, opens a PR, and then checks the worktree back used to leave the sidebar with no PR badge at all — association was strictly by checked-out branch, and the checked-out branch had none.

When the current branch resolves to no PR, Codemux falls back to branches this worktree checked out recently — up to five distinct names, newest first, read from the worktree's own reflog, excluding the current branch, the repository default branch, and detached-HEAD commits. The fallback never runs while you are on the default branch, and it badges open PRs only (the current-branch path still shows merged and closed state). Admitting history there would let a gh pr checkout of someone else's merged PR donate its badge for the whole reflog window.

A side-branch association is a badge and nothing more. It deliberately does not drive:

  • PR-completion auto-settle — that branch merging says nothing about a checkout that may still hold uncommitted work. Such a workspace still ages out through the ordinary idle rule.
  • The Wrapping up demotion.
  • The Review pane, which stays strictly current-branch so "Create Pull Request" is never hidden for the branch you are actually on.

The workspace hover card gains a PR branch row, shown only when the request's branch differs from the checked-out one. Missing information on either side reads as a match — a detached HEAD during a rebase or bisect keeps its badge — so only two known, differing branch names ever un-associate a workspace from its request.

This reflog fallback is a GitHub-path behavior; GitLab workspaces badge from the current branch only.

The Review Pane

With a request open, the pane is a header, three tabs, and an action bar.

The header carries the repo slug, #123 / !123, a state pill (Open, Draft, Merged, Closed), the title, author · age · N files · +adds −dels, and base ← head marked "checked out here". An overflow menu holds Open in browser, Copy URL, and Refresh.

TabWhat's on it
SummaryThe checks rail, reviewers, the description, and the comment threads
TimelineEverything that happened to the request, oldest first
Code (N)The full diff with existing review threads under their lines, and — on GitHub — line-level review

The tab strip is keyboard-navigable: ← / → move between tabs, Home / End jump to the first or last.

Below the body sits the pending-review footer (when you have unsubmitted notes), at most one drift notice, and the action bar. All three are covered in Reviewing & Merging.

Request data refreshes on a poll: the request and its checks every 30 seconds while checks are running, slowing to every 2 minutes once they've all reported; reviews, comments, threads, and the timeline every 2 minutes. Polling pauses while the window is hidden or after 6 minutes without activity, and picks up again the moment you're back. A failed poll never blanks the content — you get a "Showing data from 4m ago" notice with Retry now instead.

Summary

  • Checks rail — a compact rollup, with rows for only the checks that are failing or still running.
  • Reviewers — who's been asked and where they landed.
  • Description — rendered markdown, foldable past 40 lines, editable in place if you're the author.
  • Comments — the review threads. See Review threads.

Timeline

A vertical rail, oldest first, with a filter reading Everything / Host only.

Host events cover opened, reviewed (approved / requested changes / dismissed, with the comment quoted), commented, pushed (abc1234 plus subject, marked "· checks re-ran" on the newest push), force-pushed, merged, closed, reopened, review requested, and renamed. An event Codemux doesn't recognize renders as one plain line rather than being dropped.

Agent runs are the local half of the rail, marked in ember: "Agent run · addressed this thread", what it was pointed at, an optional files · +adds · −dels line, and Open thread to jump to the conversation that did the work. These are local to your install, capped at the 200 most recent, and never pushed to the host — switch the filter to Host only to hide them.

The last row is always live: "12 checks passed, 1 running", dated now.

Creating a Request

When none exists for the current branch, the pane offers Open a pull request / Open a merge request (or Commit and push first, if you haven't pushed).

The form arrives drafted from your commits:

  1. Title and Description are prefilled from the commits ahead of base — an ember note reads "drafted from your commits", and disappears the moment you type. Nothing is invented: the note never appears when the title was merely humanized from the branch name.
  2. Base branch picker — your-branch → main under the heading; changing it re-reads the commit set.
  3. N commits — the count beside the heading expands to list the commits going in.
  4. Write with agent — a chip under the description that hands the commits, a diff stat, a truncated diff, and your repo template to an agent, which writes both the title and the description. While it works the fields are read-only and the description reads "Reading the commits and the diff…"; when it answers, the note reads "drafted by agent" until you edit either field. It runs on the same agent as AI commit messages — the Agent override under Settings → Git → AI Tools if you set one, otherwise the Utility agent. If it fails, your title and description are left as they were.
  5. Use repo template — a chip that prepends your repository's PR template when it has one (GitHub's known paths; GitLab's .gitlab/merge_request_templates/).
  6. + reviewer — collect reviewers as chips; they're requested after creation. If a request fails, the PR still exists and you're told which handle didn't take.
  7. Uncommitted work is called out — "3 files have uncommitted changes" with a Review button.
  8. Draft or Create. The footer notes that it pushes the branch first.

Enter in the Title field moves to the description rather than submitting — submitting pushes the branch and publishes the request. Ctrl+Enter (Cmd+Enter on macOS) in either field creates it.

On GitLab a draft is created by prefixing the title with Draft:, which is how GitLab itself marks them.

Labels are deliberately absent — the backend can't carry them, so they aren't drawn. The agent's draft arrives all at once when it finishes; it doesn't stream into the field.

CI Checks

The Checks section shows GitHub Actions runs or GitLab pipeline jobs, summarised as a rail with only the failing and running rows expanded. Each row has a status icon, a clickable name, and elapsed time.

Expanding a failing check gives you Full log and Fix with agent. See Handing work to an agent.

On GitLab, pipelines reported by an external system fall back to commit statuses so they still appear.

There is no per-check re-run button. Re-running a job happens on the host.

Incoming Requests

On the default branch, the pane lists incoming requests targeting that base — including from forks. Click a row to open it on the Pull Requests page; use Checkout to create a worktree from the request's branch, or Switch if a workspace for it already exists.

When Something Is Unavailable

The Review pane reports the most fundamental problem first, so you're never told to install a CLI you don't need:

SituationWhat you see
Host has no integration"<Product>, read-only" with Open in browser
No remote at all"This repository has no remote yet" with Review changes (opens Changes), Check again, and a git remote add origin <url> hint
CLI missing"GitHub CLI (gh) isn't installed" with Install gh and Check again
CLI not signed in"Sign in to GitHub" — Sign in copies gh auth login to your clipboard; Check again re-reads it
Repo unreachable"Can't reach this repository" with Retry and the gh auth status command
Branch pushed, no requestOpen a pull request and View commits
Nothing pushedCommit and push (or Push branch when clean) and Changes

A repository with no remote is a normal local state, not an unsupported host. While the pane shows the no-remote, CLI-missing, or signed-out state, it checks again whenever the window regains focus and every 5 seconds for 2 minutes — so after running gh auth login or git remote add in a terminal, it usually recovers on its own.

The same gating applies to the composer's + attach menu and @issue: / @pr: mentions — those rows are disabled with the matching reason rather than failing when you click them. See Attachments.

Limitations

  • GitHub and GitLab only. Bitbucket and Azure DevOps are detected and named, but read-only with a browser link.
  • No request-changes verdict on GitLab, and no line-level review on GitLab — the Code tab there is a readable diff with no composer.
  • No deployments on GitLab.
  • Sign-in is per instance. A self-hosted GitLab on a non-default port is a separate glab entry from gitlab.com; sign in to each one you use.
  • No in-app login. Authentication is entirely gh auth login / glab auth login in a terminal.
  • No per-check re-run and no label editing on the create form.