---
url: https://clusto.app/docs/github.md
description: >-
  The GitHub view - every repository, open pull request, issue and workflow run
  of a GitHub account in one place, with review, merge, re-run and a one-tap
  hand-off to an agent in a worktree, sign-in with your Clusto account's GitHub,
  a Team pull request board, plus notifications and polling limits.
---

# GitHub

The **GitHub** view shows every repository your GitHub account can reach and
every open pull request and issue across them, plus the latest GitHub Actions
runs, on desktop and on your phone. You can read a pull request (description,
checks and their logs, conversation, changed files and diff), approve it, request
changes, comment, merge it, close it, re-run its failed checks, and hand it to an
agent in one tap. You can do the same for an issue (comment, close, reopen,
assign yourself, work on it with an agent) and for a workflow run (read job logs,
re-run, cancel). The agent hand-off is the part a browser tab cannot do: Clusto
checks the pull request out, or creates an issue worktree, in your local project
and opens a chat there.

Open it from **GitHub** in the left nav (route `/github`). The entry is hidden in
the Simple navigation profile (see [Appearance](/appearance)), and it shows a
badge with the number of pull requests waiting for your review. It is free on
every plan.

::: tip Early access
The GitHub view ships behind the `github.view` release flag, which is off by
default. Turn it on in **Settings -> Labs** (the **Early access** switch, or the
flag itself). The flag is cluster-shared, so one change covers every device
connected to the cluster. See [Feature Flags](/feature-flags).
:::

## Set up

Everything that talks to GitHub runs on one **host node** that holds your token,
so the view works the same from a phone as from a desktop, and the token never
leaves that node. Configure it once in **Settings -> GitHub**; the account list
is shared across the cluster.

1. Open **Settings -> GitHub** and add an account.
2. Fill in the fields:

| Field | Meaning |
|---|---|
| Name | A label shown in the app. |
| Host node | The node that polls GitHub and holds the token (see Security). |
| Poll interval | Seconds between polls. Default 60, allowed 15 to 3600. |
| Default merge method | Preselected in the merge dialog: merge commit, squash (default) or rebase. |
| GitHub token | Paste a personal access token. It is saved to the host node only. |

3. Instead of pasting a token you can press **Import from gh CLI**. The host node
   runs `gh auth token` for the OS user you pick (default: the node's default
   session user), stores the result like a pasted token, and never logs it. The
   `gh` CLI must be installed and signed in (`gh auth login`) on the host node.

Clusto asks GitHub which account the token belongs to when you save it and shows
**authenticates as `<login>`**. That login decides what "mine" means in the view:
the **Needs my review**, **Mine** and **Assigned** buckets and the notifications
all key off it.

If you add more than one account, the view shows an account picker.

### Use your Clusto account's GitHub sign-in

Instead of pasting a token you can reuse the GitHub account linked to your
[Clusto account](/accounts-licensing). This works on every plan.

1. Sign in to your Clusto account in the app (Settings -> Account).
2. In **Settings -> GitHub**, press **Use my Clusto GitHub sign-in**.
3. The first time, GitHub is not yet linked with repository access, so Clusto
   opens `clusto.app/account/connect-github` in your browser. Sign in there if
   asked, press **Connect GitHub**, and grant the `repo` and `read:org` scopes.
   Then return to the app and press **Use my Clusto GitHub sign-in** again.
4. Clusto asks your Clusto account for the GitHub token and sends it write-only
   to the host node, exactly like a pasted token. This device never keeps it.

Things to know:

* The GitHub account must have the same email as your Clusto account. If it does
  not, the link fails; use a personal access token instead.
* Organisations that restrict third-party apps hide their repositories from the
  Clusto OAuth app until it is approved, and GitHub gives no error for it, so
  they are simply missing from the list. On GitHub open Settings > Applications >
  Authorized OAuth Apps > Clusto and press **Grant** next to the organisation
  (**Request** if you are not an owner), then refresh the GitHub view. The
  **Missing an organisation's repositories?** panel under the Repositories tab
  and in Settings > GitHub links straight there, as does the F1 command
  **GitHub: grant organisation access**. An imported gh token is the GitHub CLI
  app instead, which most organisations already allow.
* The token is stored encrypted in your Clusto account. See
  [Account Cloud Sync](/cloud-sync#github-token). Unlinking GitHub or revoking the
  app on GitHub makes the next attempt ask you to connect again.
* This token is an OAuth token with the `repo` scope, so it covers every
  repository your GitHub account can reach, not one owner. The fine-grained
  permission list below applies to pasted tokens only.

### Security: where the token lives

A GitHub token can write to every repository it covers, so whoever can read it
can approve and merge as you. So:

* **The host node must be a node your agents cannot read.** Never use the
  machine the agents run on. The token is stored on the host node only. It is
  write-only: Clusto never sends it back to any client, never replicates it to
  other nodes and never logs it.
* **Use a fine-grained personal access token** with these repository
  permissions: Pull requests read and write, Contents read and write (write
  to merge, and for the factory to push), Checks read, Commit statuses read,
  Issues read and write (read to list issues, write to comment, close, reopen
  and assign), Actions read and write (read for job logs and runs, write for
  re-running and cancelling), and Metadata read. Leave Workflows off.
  **Create token on GitHub**, under the token field, opens GitHub's new-token
  page with these permissions, a name and a one-year expiry filled in; for a
  Factory account it also sets the resource owner to the account's
  organization. Review the page, pick the repositories, generate the token
  and paste it back. A fine-grained token covers one owner at a time
  (your user or one organisation); use a classic token with the `repo` scope
  if you want one token across several owners.
  A Factory account works only inside its organization; the
  [software factory](/factory) can also start items on its own from open issues
  that carry the repository's `intake_label` (GitHub only).
* Every action you take on a pull request, issue or workflow run is written to
  the host node's audit log (`github_action`) with the account, repository,
  number (the workflow run id for runs) and action. The action kinds are:

  | Target | Kinds |
  |---|---|
  | Pull request | `approve`, `request_changes`, `comment`, `merge`, `close`, `reopen`, `mark_ready`, `rerun_failed_checks` |
  | Issue | `issue_comment`, `issue_close`, `issue_reopen`, `issue_assign_me` |
  | Workflow run | `run_rerun_failed`, `run_rerun`, `run_cancel` |

  Each entry also records whether the action succeeded (`ok=true` or `ok=false`).

If the host node is offline the view shows the last data it has, marks it read
only, and hides the actions. No other node polls GitHub, because only the host
has the token.

## Overview

The **Overview** tab is the first tab and the one the view opens on. It is an
at-a-glance dashboard of widgets. Every widget shows its first 5 items and has a
**View all** button that opens the matching tab with the right filter already
applied.

| Widget | Shows | Default |
|---|---|---|
| Review requested | Pull requests waiting for your review. | On |
| Failing workflows | The latest finished run of each workflow and branch that failed. Pull request runs are left out, because they show on their pull requests. | On |
| My pull requests | Open pull requests you opened. | On |
| Issues assigned to me | Open issues assigned to you. | On |
| Running workflows | Workflow runs that are queued or running. | Off |
| Repositories | Your repositories. | Off |

Press **Customize** to choose which widgets show, reorder them and set each one
to half or full width (the width applies on wide screens; on a narrow window and
on a phone the widgets stack). The layout is a synced preference: it is saved
with your account settings and follows you to your other devices (see
[Cloud Sync](/cloud-sync)). The palette has **GitHub: customize the overview**
for the same dialog.

## Pull requests

The **Pull requests** tab lists every open pull request. On desktop it is a list beside the
detail pane (drag the divider to resize); on a phone a selected pull request
replaces the list and **Back** returns to it. Pull request and issue buckets,
filters, the runs filter and repository search are remembered on this device and
reset when you switch GitHub account.

The bucket chips above the list show a count each:

| Bucket | Shows |
|---|---|
| Needs my review | Pull requests where you are a requested reviewer. |
| Mine | Pull requests you wrote. |
| Assigned | Pull requests assigned to you. |
| Team | Pull requests written by, or waiting on a review from, your teammates. Team plan only; see below. |
| All | Every open pull request in the visible repositories. |

The personal buckets need the token's login. Until the host has a token, the view
falls back to **All**.

### Team pull request board

The **Team** bucket appears only when you are signed in to a Clusto account that
holds a seat on an active [Team plan](/accounts-licensing#pro-and-team-billing).
It lists open pull requests that a teammate wrote or was asked to review, so a
team sees what is moving across the whole group in one place.

* A teammate counts once they have linked GitHub to their Clusto account (see
  above). Until then the bucket says that teammates appear after they connect
  GitHub.
* Matching is by GitHub user id, which survives a login rename. Your own pull
  requests stay in **Mine**, not **Team**.
* Teammates see only your display name and GitHub user id; no email or token
  leaves the server. The list is fetched once per sign-in and needs no extra
  GitHub requests.
* Without a Team plan the bucket is hidden, and the other buckets work as before.

Narrow the list with the search box (title, repository, author, branch or
number), the owner picker (organization or user), the repository picker (type
in its search box to find a repository; it lists only the chosen owner's), the drafts picker (**With drafts**,
**Hide drafts**, **Drafts only**) and the **Failing** toggle, which keeps only
pull requests whose checks failed. Each row shows the repository and number,
author, how recently it changed, a checks chip, a **Draft** badge, the review
decision (**Approved** or **Changes requested**) and **Review requested** when
it waits on you.

### Pull request detail

Open a pull request to see:

* **Description** - the body, rendered as safe Markdown.
* **Checks** - every check run on the head commit with failed ones first, then
  running, then passed. For a GitHub Actions job, **Log** shows the tail of its
  log (the last 64 KiB; open GitHub for the rest). The external-link button
  opens the check on GitHub.
* **Conversation** - reviews and comments in time order, with each review's
  verdict. Empty plain reviews are left out.
* **Files** - the changed files with a per-file diff. Very large pull requests
  are cut to size caps and say so, with a link to the rest on GitHub.

The header shows the state (**Open**, **Draft**, **Closed**, **Merged**), the
review decision and a **Conflict** badge when the branch cannot merge cleanly.

### Actions

The action bar appears when the host is online and has a token. Every action
asks for confirmation or a message first.

| Action | What it does |
|---|---|
| Approve | Submits an approving review, with an optional note. |
| Request changes | Submits a review that blocks the merge. A message is required. |
| Comment | Posts a conversation comment (Markdown). |
| Merge | Merges with the method you pick (the account's default is preselected). Clusto sends the head commit it just read, so a push that lands while the dialog is open makes GitHub refuse instead of merging unreviewed code. |
| Ready for review | Takes a draft out of draft state. Only shown on drafts. |
| Re-run failed | Re-runs the failed jobs of every GitHub Actions workflow run behind a failed check. Only shown when an Actions job failed. |
| Close / Reopen | Closes an open pull request or reopens a closed one (not a merged one). |

Review and comment bodies are limited to 64 KiB. If GitHub refuses an action
(for example the branch is protected or has conflicts) the reason is shown and
nothing changes.

## Issues

The **Issues** tab lists the open issues of your visible repositories (pull
requests are left out, although GitHub counts them as issues). Like the pull
request list it is a list beside a detail pane on desktop and a stacked page on a
phone.

| Bucket | Shows |
|---|---|
| Assigned to me | Issues assigned to your login. |
| Mine | Issues you opened. |
| All | Every open issue in the visible repositories. |

Narrow the list with the search box (title, label, author, repository or number)
and the owner and repository pickers. A row shows the repository and number, title,
labels, author, comment count, how recently it changed and an **Assigned to me**
badge. Issues of repositories that are neither pinned, busy nor recently pushed
are read less often; see Polling and rate limits.

Open an issue to read its description (safe Markdown) and its comments. The
action bar offers:

| Action | What it does |
|---|---|
| Work on with agent | Opens the agent dialog (below). Only on open issues. |
| Comment | Posts a comment (Markdown, up to 64 KiB). |
| Assign me | Adds your login to the assignees. Hidden when you are already assigned. |
| Close | Closes the issue after a confirmation. |
| Reopen | Reopens a closed issue. |

### Work on an issue with an agent

Pick a local project (linked projects first, as for pull requests). Clusto then,
on that project's node:

1. Fetches the repository's default branch from `origin`, then creates a
   worktree `worktrees/issue-<number>` on branch `wt/issue-<number>`, starting at
   the freshly fetched `origin/<default branch>`. A failed fetch is an error and
   no worktree is created, so the agent never starts from a stale base. See
   [Worktrees](#worktrees-and-the-base-ref).
2. Starts a chat on that node with the worktree attached, using the agent and
   model of your last chat, and sends the brief as the first message: issue
   title, link, author, labels, the start of the description and the latest three
   comments.

The brief asks the agent to read the code first, make the change with tests and
commit on the checked-out branch. It tells the agent not to push, open a pull
request or comment on GitHub, so you review before anything leaves your machine.
If `worktrees/issue-<number>` already exists the hand-off stops with git's error;
remove or reuse that worktree first.

## Actions

The **Actions** tab lists the latest GitHub Actions workflow runs (up to ten per
repository) of your visible, active repositories, newest first. A row shows the
state, workflow name, run title, repository, branch, event, who started it, how
recently, the attempt number when it was re-run, and chips for the pull requests
the run belongs to.

Filters: search (workflow, title, branch, repository), the owner and repository
pickers, **Failing** (completed runs that failed) and **Mine** (runs you started;
needs the token's login).

Open a run to see its jobs, failed ones first, then running, then the rest. Each
job has a **Log** button that shows the tail of its log (the last 64 KiB) and a
button that opens the job on GitHub. The action bar offers:

| Action | What it does |
|---|---|
| Re-run failed | Re-runs only the failed jobs. Shown on a finished run with a failed job. |
| Re-run all | Re-runs every job. Shown on a finished run. |
| Cancel | Cancels a queued or running run after a confirmation. |
| Pull request #n | Jumps to a pull request the run belongs to. |

Re-run and cancel need Actions write access, and are hidden while the host is
offline or has no token.

## Repositories

The **Repositories** tab lists every repository the token can see, user and
organisation, with a search box. Pinned repositories come first, then the most
recently pushed. A row shows the description, last push, an open pull request
count, the default branch's check state, and **Private**, **Archived** and
**Fork** marks.

* **Pin** keeps a repository at the top and always counts it as active for
  polling.
* **Hide** removes it from the view and stops polling its pull requests. Hiding
  also unpins. Unhide it under **Settings -> GitHub -> Hidden repositories**.
* Tapping the **open pull request** count jumps to the Pull requests tab
  filtered to that repository.
* **Linked projects** - each node reports which of its Clusto projects have a
  `github.com` remote matching the repository. Those projects appear as chips on
  the row (and in the agent dialog); tap one to open the project in the Files
  view. The agent dialog preselects the project you last started from for that
  repository, else the first linked one.

## Review with an agent, Fix failing CI

Two buttons on an open pull request hand it to an agent:

* **Review with agent** - available on every open pull request.
* **Fix failing CI** - available when at least one check failed.

Pick a local project (the ones that check out this repository are listed first;
any project works if its `origin` is the same repository). Clusto then, on that
project's node:

1. Fetches the pull request head from `origin` and checks it out in a new
   worktree `worktrees/pr-<number>` on branch `wt/pr-<number>`. If the worktree
   already exists it moves to the latest head (git refuses if local edits
   conflict). Nothing is pushed.
2. For **Fix failing CI**, reads the tail of the log of each failed Actions job.
3. Starts a chat on that node with the worktree attached, using the agent and
   model of your last chat, and sends the brief as the first message: pull
   request title, link, author, branch, size and the start of the description,
   then either the review instructions or the failing check names and log
   tails.

The review brief tells the agent not to push, comment on GitHub or merge. The fix
brief asks for a commit on the checked-out branch and tells it not to push, so you
review and push. Change the default agent in **Settings -> Chats**.

## Notifications

The host node records three alert kinds in the durable notification log (see
[Background Notifications](/background-notifications)):

| Kind | When |
|---|---|
| `github_review_requested` | Your login newly appears among a pull request's requested reviewers. |
| `github_checks_failed` | Checks on a pull request you wrote turn failed (once per head commit). |
| `github_pull_update` | A pull request you wrote is approved, merged or closed. |

Each kind has its own switch under **Settings -> Notifications -> GitHub** and is
per device: a device mutes a kind by sending `<kind>=off` on its `/notifications`
poll. The body reads `owner/name #123: title`, and tapping
the alert opens that pull request.

The first poll of an account only records the current state, so turning the view
on does not flood you with alerts for pull requests that already exist. The
cursor is kept on the host, so a restart neither repeats nor drops alerts.

## Polling and rate limits

The host node polls GitHub every 60 seconds by default (your poll interval) and
keeps polling when no client is connected. Requests are conditional (they send
the previous ETag) and a `304 Not Modified` answer does not count against
GitHub's rate limit, so an idle repository costs no budget. In detail:

* The repository list is reread every 10 minutes.
* Open pull requests are read on every poll for **active** repositories: pinned,
  having open pull requests, or pushed in the last 14 days. Quiet repositories
  are read every 10 minutes.
* Open issues and the latest workflow runs are read for active repositories only.
  They are read on every poll for **pinned** repositories and for repositories
  whose previous read showed a queued or running workflow run, so a running CI
  keeps updating. Every other active repository is read every 10 minutes.
* Check state is fetched only when a pull request's head commit changes, and
  reviews only when the pull request changed.
* While a check on one of your own pull requests, or a workflow run you started,
  is running, polling speeds up to **15 seconds**.
* When the remaining budget drops below 200 requests, polling slows to one poll
  every 5 minutes.
* When GitHub rejects the token (`401`, or a `403` that is not a rate limit,
  for example a revoked or expired token), the view shows "GitHub rejected the
  token" with the reason and stops regular polling. The host retries after 2
  minutes, then doubles the wait up to once every 30 minutes, and logs the
  rejection once. Saving a token in **Settings -> GitHub**, or the refresh
  button, tries again at once; the first good poll resumes normal polling.

Expect a few hundred requests per hour for about 60 repositories with 15 open
pull requests, mostly free `304` answers, well under GitHub's 5000 per hour.
Pinning many repositories raises this, because each pinned repository also reads
its issues and workflow runs on every poll. The
view header shows who you are signed in as, when it last synced, how many
requests are left, and **Fast polling** while the 15 second interval is on. The
refresh button polls immediately.

## F1 command palette

When the flag is on, the palette has **Go to GitHub**, **Refresh GitHub** and
**GitHub settings: accounts, token, host node**. Inside the view it adds the tabs,
**GitHub: customize the overview**,
the pull request and issue buckets (including **Team** on a Team plan), the
failing toggles for pull requests and workflow runs and **Only my workflow runs**.
With a pull request open it adds **Open #n on GitHub**, **Comment on #n**,
**Approve #n**, **Request changes on #n**, **Merge #n**, **Review #n with an
agent** and **Fix failing CI of #n with an agent**. With an issue open it adds
**Open issue #n on GitHub**, **Comment on issue #n**, **Work on issue #n with an
agent**, **Assign issue #n to me**, **Close issue #n** and **Reopen issue #n**.
With a workflow run open it adds **Open run on GitHub**, **Re-run failed jobs of
the run**, **Re-run every job of the run** and **Cancel run**.

## Ask the Assistant

The [Clusto Assistant](/assistant) has a read-only `clusto_github_prs` tool. It
lists the open pull requests across your accounts (repository, number, title,
author, draft, check status, review decision, requested reviewers and whether one
waits on your review), plus sync errors, optionally filtered by repository or
account. Each account also reports `failing_workflow_runs`, the number of its
latest workflow runs that finished with a failure (counted for the same
repository filter), so the Assistant can tell you CI is red without listing
every run. Pull request titles are written by other people, so the Assistant treats
them as data. To act on a pull request it points you at this view.

## Worktrees and the base ref

Creating a worktree from `origin/<branch>` now fetches that branch from `origin`
first (`git fetch --no-tags origin <branch>`), so the new worktree starts at what
the remote has right now rather than at the last fetch. This applies to every
worktree created from a remote-tracking base, not only the issue hand-off. A
failed fetch (offline, no credentials, unknown branch) is reported as an error
and no worktree is created; Clusto never silently falls back to a stale ref. A
base that is a local branch, tag or commit is used as given and fetches nothing.
Pull request worktrees (`worktrees/pr-<number>`) fetch the pull request head
instead, as described under Review with an agent.
