> ## Documentation Index
> Fetch the complete documentation index at: https://continuum-three-olive.vercel.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Diffs & PRs

> Live git diff with per-hunk staging, inline PR review comments, and GitHub PR status, create, approve, and merge — without leaving the workbench.

Continuum keeps a live view of what the agent has changed and where the pull request stands. The diff comes straight from `git`; PR status and actions come from the GitHub CLI (`gh`) running on the host the session runs on.

## Live diff

The Diff pane reflects the working tree of the session's repo — its worktree when the session runs in worktree mode, otherwise the repo root.

It runs three `git` invocations and merges the results so staged and unstaged changes stay distinct:

* `git diff --unified=3` — unstaged changes.
* `git diff --cached --unified=3` — staged changes.
* `git ls-files --others --exclude-standard` — untracked files, rendered as synthetic "new file" diffs.

<Note>
  Continuum deliberately avoids `git diff HEAD`, which flattens staged and unstaged deltas into one patch. Keeping them separate means a Revert on an unstaged hunk can't accidentally hide a staged change that's still commit-ready in the index.
</Note>

### Auto-refresh

The Mac diff store watches the repo's `.git` directory with a vnode source (`write`, `extend`, `attrib`, `rename`, `link`). Anything that touches the index, `HEAD`, or refs lands there, so when the agent stages or writes files the diff re-runs on its own. Three things keep that from thrashing:

* Refreshes coalesce on a **100 ms** window, so a burst of edits doesn't re-spawn `git` repeatedly.
* When a filesystem event produces no actual change, the store backs off — doubling up to a **15-second** ceiling, and resetting the moment real content moves. An agent writing continuously to a busy worktree can't pin a `git` subprocess per event.
* A **5-second** poll runs alongside the watch as a backstop for changes the vnode source misses.

### Per-hunk and per-file actions

Each file expands into its hunks. The available actions depend on the change state — no terminal required:

| Change state | File actions  | Hunk actions  |
| ------------ | ------------- | ------------- |
| Unstaged     | Stage, Revert | Stage, Revert |
| Staged       | Unstage       | Unstage       |
| Untracked    | Stage, Trash  | —             |

* **Stage / Unstage** pipe a per-hunk or per-file patch into `git apply --cached` (forward to stage, `--reverse` to unstage). Staging a whole untracked file uses `git add` instead.
* **Revert** on an unstaged change reverse-applies the patch to the working tree, removing only that change without touching the index. On a staged change it reverse-applies to the index, which is an unstage, not a destructive revert.
* **Trash** on an untracked file moves it to the system Trash — recoverable, not a hard delete — and asks for confirmation first. It refuses any path that resolves outside the repo.

### Inline PR review comments

When the branch has an open PR, the Mac diff pane pulls its GitHub review comments and renders each one **on the line it was left on**, threaded with its replies. You can post a new line comment or reply to an existing thread from the diff itself, and jump to the comment on GitHub. The comment poll runs every 30 seconds while a PR exists and drops to every 2 minutes when there isn't one, so a branch with nothing to sync isn't spawning `gh` continuously.

### Commit sheet

When you're ready to commit, the **Commit…** button opens a sheet. Submitting runs `git commit -m <message>` against the session's repo. Continuum commits exactly what's staged — it does not auto-stage on your behalf.

The diff surfaces:

* **Mac:** the Code workbench review pane → **Diff** tab.
* **iPhone:** the **Diff** tab of the session workbench, served by `GET /sessions/:id/diff` (truncated files lazy-fetch full hunks via `GET /sessions/:id/diff/<path>`). Stage / Unstage / Discard are file-level here and route through `POST /sessions/:id/diff-action/<path>`. There is no commit sheet on iPhone — commit from the Mac.

## PR status

Continuum resolves a session's PR status two ways, with the host poll as the authority.

### Host poll (primary)

The Mac polls the host's `GET /sessions/:id/pr` endpoint about once a minute, with jitter so many sessions don't stampede together. The host resolves the session's current git branch and runs:

```
gh pr list --head <branch> --state all --limit 1 --json url,number,title,body,state,isDraft,additions,deletions,changedFiles,reviewDecision,statusCheckRollup
```

If the branch can't be resolved it falls back to `gh pr view`. This reports title, body, and number; state (open / draft / closed / merged); additions, deletions, and changed files; the review decision; and a status-check rollup.

Answers are cached on the host with a short TTL and shared across clients, so your Mac, phone, and the web app all read one `gh` result rather than three. The cache is deliberately **stale-tolerant**: when a probe fails, the last known answer keeps being served instead of collapsing to "no PR." A host with a broken or unauthenticated `gh` can no longer wipe a good PR badge for every device at once.

Because the host checks the branch directly, it knows a PR is open even when the agent only *mentioned* it in prose — so the titlebar shows the open PR link instead of still offering "Create PR."

### Chat-scan mirror (fallback)

When no host client is available — or the host temporarily doesn't recognize the session id during a launch or restart race — Continuum scans the chat transcript for a `https://github.com/<owner>/<repo>/pull/<n>` URL, using creation-context heuristics so it latches the PR this session created rather than an unrelated PR cited in passing. You can also paste a PR URL manually to pin the mirror to a specific PR.

## PR actions

### When Create PR is offered

One rule decides this, shared by the Mac titlebar, the iPhone header, the iPhone overflow menu, and the web and Android clients, so no two surfaces can disagree:

1. The session runs in a **worktree**.
2. **No provider turn is in flight.** This is broader than "not streaming" — a prompt a client has already accepted but the host hasn't started streaming yet still counts as a turn in flight. That gap is why the phone used to re-offer Create PR for the whole send round-trip while the Mac didn't.
3. The transcript **has provider messages** — there is something to open a PR about.
4. The session already has **no PR**.

Remote clients add one more condition: the session's host must actually advertise PR support. A host that can't open PRs — an older agent, or a session with no live control path — gets no Create affordance from your phone at all. Offering a button that 404s is worse than offering nothing.

An existing PR's pill shows regardless of turn state, so you can always jump to the PR mid-turn.

### On Mac — the Code titlebar

* **Create PR** sends the agent a "Create PR" instruction with the PR-instructions skill attached, and auto-sends it. The agent opens the PR; the poll then detects it and flips the titlebar to a live **#number** link. A menu option creates a **draft** PR instead. The skill's text comes from `.context/PR instructions.md` in your repo when present, and falls back to Continuum's own canonical workflow otherwise.
* **Open PR** opens the linked PR in your browser.
* **Merge** appears when the PR is open and its checks are green or haven't reported. Before merging, Continuum creates a safety checkpoint; if the checkpoint fails, the merge is cancelled. Merge is additionally blocked while the session has open TODOs.

### Host endpoints

The mobile, web, and Merge paths go through the host, which shells out to `gh`:

* **Create** — `POST /sessions/:id/create-pr` runs `gh pr create --fill`, honoring an optional title, body, and base branch.
* **Review / Approve** — `POST /sessions/:id/pr/review` runs `gh pr review` with `--approve`, `--comment`, or `--request-changes`.
* **Line comments** — `GET`/`POST /sessions/:id/pr/comments` read and write GitHub review comments, including replies.
* **Merge** — `POST /sessions/:id/merge` runs `gh pr merge <n>` with the chosen method (`--squash` default, `--merge`, or `--rebase`), plus optional `--delete-branch` and `--auto`. The host refuses to merge when checks are failing or pending unless you pass an admin override.

### Idempotent writes

Every write carries an idempotency key, and the host's command outbox makes retries safe:

* A retried request with the **same key** replays the cached response instead of re-running the side effect — so a tap that times out and retries does not create a second PR or merge twice.
* A duplicate request for a key that's still **in flight** returns `409`.
* Reusing a key with a **different payload** returns `422`, catching a retry whose body was edited between taps.

## Beyond the Mac

PRs are not Mac-only. The Go host agent that powers the Windows and Linux desktop apps, the `continuum` CLI, VPS hosts, and managed runners implements the same session routes — create PR, merge, approve, and read/write review comments — by shelling out to `gh` **on that host**. A session running on a Linux box opens its PRs from that Linux box.

<Warning>
  The GitHub CLI must be installed and authenticated on whichever machine runs the session, not on the device you're looking at. Run `gh auth status` there to check, and `gh auth login` if needed. Without `gh`, PR status, create, approve, and merge are all unavailable — the host returns `503` with an install hint.
</Warning>

## On iPhone

The session workbench mirrors the same data through its **PR** tab. It offers:

* **Create PR** and **Merge** — both queue through the [command outbox](/docs/surfaces/mobile), so a tap survives the host being briefly unreachable and retries with backoff instead of being silently dropped. The merge sheet lets you pick the method (squash / merge / rebase) and toggle delete-branch and auto-merge.
* **Review** (Approve / Comment / Request changes) — submitted directly to the host's idempotent review endpoint.

Merge is disabled in the UI, with a reason, when the PR's checks haven't passed.

## Related

* [Sessions](/docs/features/sessions) — the session runtime and worktree setup.
* [Code](/docs/surfaces/code) — the Diff tab and titlebar PR control in the Code workbench.
* [Mobile](/docs/surfaces/mobile) — the command outbox and session workbench tabs.
* [Remote devices](/docs/features/remote-devices) — the non-Mac hosts that run these same endpoints.
