> ## Documentation Index
> Fetch the complete documentation index at: https://docs.attensira.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub

> Install the Attensira GitHub App and the agent opens pull requests against your site's repositories, as drafts by default. It never pushes twice, and merges only when you press Merge in your Inbox, or a safe change when you switched on auto-merge.

## What the GitHub connection is

Attensira finds things worth fixing on your site. GitHub is how a fix leaves the product and arrives somewhere you can review it: the agent opens a **pull request** against the repository the page actually lives in.

This is a first-party **GitHub App**, installed by you into your organisation or account. It is not an OAuth app, and it is not brokered through a third-party connector — the App is ours, the installation is yours, and you can see and revoke it from GitHub's own settings at any time.

## Connecting the App

<Steps>
  <Step title="Install the App">
    From the project's GitHub settings, press **Connect GitHub**. GitHub takes over and asks which account or organisation to install into.
  </Step>

  <Step title="Choose the repositories">
    Grant the App **only selected repositories**, and pick the ones whose content you want changed. GitHub, not Attensira, holds this list — changing it later is done on GitHub's installation page.
  </Step>

  <Step title="Attach them to the project">
    Back in Attensira, choose which of the installed repositories this project may open pull requests against.
  </Step>
</Steps>

### Where your site lives in the repository

Your site does not have to be at the repository root. A framework config file up to two directories deep, such as `src/next.config.mjs` or `apps/web/next.config.ts`, is detected, and content roots are reported relative to the repository.

**A project can have several repositories.** That is the normal case, not an edge case: a marketing site, a docs site and the app itself are often three separate repos, and a finding on `/pricing` belongs in a different one from a finding on `/docs/quickstart`. Attach all of them and each pull request goes where its page lives.

## What we do and do not do

<Warning>
  We open pull requests. Beyond that we only take one of ours out of draft or merge it, under the rules below. That is the whole of our write access to your codebase.

  * We **merge only when you press Merge** in your [Inbox](#merging-from-your-inbox), or when you switched on [auto-merge for safe changes](/agent/approval#auto-merge-for-safe-changes). Your Merge is pinned to the commit you reviewed; auto-merge merges only a safe change, at the commit we pushed. Either way, only once GitHub says every required check and review is satisfied.
  * We **never push to your default branch**. Every change is on a fresh branch of ours.
  * We **never push twice to the same branch**. One finding, one branch, one push — a pull request we opened is final from our side.
  * We **never touch CI configuration**, workflow files, or anything else that changes how your builds run.
</Warning>

The point of those four rules is that the pull request is the whole surface. Nothing we do can change once you are looking at it, so reviewing our diff is reviewing the final thing.

## Permissions we request

Exactly three, and no others:

| Permission | Access | What it is for |
| - | - | - |
| Contents | Read and write | Read the files behind a page, and push our branch |
| Pull requests | Read and write | Open the pull request, and read its state afterwards |
| Metadata | Read | Mandatory for every GitHub App; lists the repositories you granted |

There is no Actions permission, no Administration permission, and no access to secrets. If GitHub's consent screen shows you something not on this list, you are not installing our App.

### If you cannot install it yourself

Most people who pay for Attensira cannot merge to their own site. That is the normal case, and the agent has a path for it: it writes the fix as a **rewrite**, the passage as published beside a better version of it, instead of a pull request.

On any rewrite in your Inbox there is **Request access from my developer**. Type their email and Attensira writes the ask for you: what the change is, a private link to the rewrite so they can read it before deciding, the install link, the three permissions above, and the four things we never do.

**We do not send it.** The email is written as a draft in your own mailbox (Gmail or Outlook, through the mailbox you connected on the Plugins page), addressed to whoever you named. You read it, change it, and send it, or do not. If you have no mailbox connected, Attensira hands you the text and opens it in your own mail app instead.

Once the App is installed, the same findings arrive as pull requests instead of rewrites.

## What we may change in a file

Pages written in Markdown, MDX and HTML are edited under the [change classes](/agent/approval#what-attensira-changes-on-its-own-and-what-it-always-asks-about). Source files are different:

* In `.ts`, `.tsx` and `.js` files we may edit **only the words inside string literals**: titles, descriptions, copy in data files. Such a change always waits for a person (class **claim**, rule `source-copy`).
* A literal that is code is refused as source: an `import` or `require` path, a `'use client'` or `'use server'` directive, a raw-HTML (`__html`) payload, or an evaluator's argument.
* Any other change to a source file is refused.

If a page's title lives in a file outside your content roots (in `src/lib`, say), the agent says so rather than editing it. Add that directory as a content root and the next proposal can reach it.

## How a finding becomes a pull request

<Steps>
  <Step title="A finding">
    The agent identifies something to fix on a page — a missing answer to a tracked prompt, a claim that has gone stale, a page with nothing citable on it.
  </Step>

  <Step title="The source file">
    It locates the file that produces that page in one of the attached repositories, including where the page's title and description are defined. A finding whose source it cannot find does not become a pull request; it becomes an [Inbox](/agent/inbox) row saying so. A proposal for a path that does not exist yet, such as a new blog post under a content root, creates a new file.
  </Step>

  <Step title="An edit and a branch">
    It writes the change and pushes it to a new branch. The branch is created for this finding and is used once.
  </Step>

  <Step title="A pull request">
    It opens the pull request against your default branch, with a body that says which page, which finding, why this edit answers it, and whether it will auto-merge — and applies the `attensira` label.
  </Step>
</Steps>

Approval rules apply here as they do everywhere else the agent writes outward: if the project requires your yes before an outward write, the pull request is not opened until you give it. See [what the agent shows you](/agent/what-the-agent-shows).

## What happens after the pull request

We keep watching it. Attensira tracks whether the pull request was **merged** or **closed**, and what your **CI** said about it, and shows that on the row in your [Inbox](/agent/inbox).

<Warning>
  **A red build or a merge conflict is surfaced to you and left there. We do not push again.**

  The no-second-push rule has no exception for fixing our own work. If checks fail, or the branch conflicts with something that landed after we opened it, the Inbox row will tell you — and then nothing further happens until a human acts. Nobody should sit waiting for a follow-up commit that is not coming.
</Warning>

What to do with one is your call: push a commit onto our branch yourself, close the pull request, or resolve the finding some other way and mark the Inbox row **Done**. Once GitHub says it can merge, you can [merge it from your Inbox](#merging-from-your-inbox).

**Closing an Attensira pull request without merging declines the work item** ("closed without merging"), and we do not open it again. Reopening the pull request brings the item back.

The item's activity reads "Opened pull request #N … goes live when it is merged and deployed", not "Published": a pull request is not a live page. Once it merges, the tracked prompts attached to it (the `prompt_ids` the agent gave `propose_fix`) are [re-read](/measure/before-and-after) at +7, +14 and +30 days. Without attached prompts, no before-and-after is measured.

## Reviewing a pull request in Attensira

You do not have to leave for GitHub to see what a pull request of ours would merge. Open the item in your [Inbox](/agent/inbox): once the change is approved and its pull request exists, the item's detail shows that pull request **read live from GitHub** at the moment you opened it. Nothing in it is a stored copy, and it is read only for the item you open, never for the whole list.

What the panel shows:

* **The title and description**, as GitHub holds them now. Anyone with write access to the repository can edit a description, so only basic formatting is drawn, only web and mail links become links, and nothing in it runs.
* **Every changed file**, with GitHub's own diff. Up to 300 files are listed, and one file's diff is cut at 64 KB; either cut says so and links to the full diff on GitHub. A binary file, or a diff GitHub itself will not render, is listed without a diff.
* **The checks** on the branch's latest commit: check runs and commit statuses in one list, each with its state (**Failing**, **Running**, **Passed** or **Neutral**) and a link to its own page. If the installation cannot read checks or commit statuses, the panel says which read was refused in place of the list. An empty list means nothing ran; a missing list means we could not read it.
* **A deploy preview**, when one of those checks or statuses links to a preview on `*.vercel.app`, `*.netlify.app` or `*.pages.dev`. We do not read GitHub's deployments, so a preview your hosting reports only there does not appear.
* **Someone else's commits.** If the branch's latest commit is no longer the one we pushed, the panel says so: their commits are in the files shown, and in what a merge would merge.
* **Why it cannot merge yet**, in one sentence, whenever GitHub says it cannot:

| GitHub's state | What the panel says |
| - | - |
| Draft | It is still a draft on GitHub |
| Conflicting | It conflicts with `<base branch>` |
| A check failing | A check is failing: `<check names>` |
| Blocked by branch protection | A required review or check is missing |
| Behind its base | The branch is behind `<base branch>` |
| Not decided yet | GitHub is still checking whether this can merge |

If GitHub does not answer, the panel says so and keeps the **Open on GitHub** link, which still works. If the repository has been disconnected from the project since, the pull request can only be opened on GitHub, and the panel says that instead.

## Merging from your Inbox

Approving the change is what opened the pull request. **Merging it is a second, separate yes**, and you can give it without leaving Attensira, from the [panel above](#reviewing-a-pull-request-in-attensira). Under the pull request there is at most one button, only while the pull request is open on an approved item, and it depends on where the pull request is:

<Steps>
  <Step title="Mark ready for review">
    Shown while the pull request is a draft, which is how [new repository connections open them](#how-your-merge-automation-interacts-with-us). It takes the pull request out of draft on GitHub and does nothing else: no commit, no merge. If your repository merges ready pull requests on its own (GitHub auto-merge, a merge queue or a bot), that may merge it without another click from you; the confirmation says so before you press it. Like Merge, it is refused if the branch moved since you looked.
  </Step>

  <Step title="Merge">
    Shown once it is out of draft. It squash-merges the pull request into its base branch, at the commit you were looking at. Anything that deploys from that branch ships it.
  </Step>
</Steps>

Each button asks once, inline, before it acts. Neither is ever pressed by the agent, and there is no "approve and merge" in one click.

**Merge goes ahead only when all of these hold:**

* The pull request is still open. One that was closed without merging is refused.
* Its branch is still at the commit you reviewed. If anyone pushed since, nothing is merged, the panel is read again, and it says **The branch changed. Review it again.**
* It is not a draft.
* GitHub reports it mergeable with nothing in the way. Otherwise Merge is greyed out, with the sentence from the [table above](#reviewing-a-pull-request-in-attensira) beside it. A failing check blocks Merge even when your branch protection does not require it: fix the check, or merge on GitHub.

You may merge a change of any [class](/agent/approval#what-attensira-changes-on-its-own-and-what-it-always-asks-about), including one classed **claim** that would never merge on its own: the click is your yes to that specific merge.

**Pressing Merge twice is safe.** If the pull request is already merged, the second press reports it merged and does not merge again. The item's activity records "Merged pull request #N by" the person who pressed it.

A merge from here is recorded the same way as a merge on GitHub: the row moves to merged, and its [re-reads](/measure/before-and-after) are booked, only when GitHub reports the merge back to us.

Merging and marking ready are a signed-in person's clicks in the dashboard. The [REST API](/api/overview) and the [MCP server](/mcp/overview) cannot merge a pull request or take one out of draft, and neither is offered to an assistant.

## How your merge automation interacts with us

We open a pull request. Your branch protection and merge automation decide what happens next — **if your repo auto-merges on green, a pull request of ours that is ready for review will merge too.**

Two controls make this predictable:

* **Draft mode (`open_as_draft`).** New repository connections open pull requests as GitHub **drafts by default**. Most merge automation ignores drafts, so nothing of ours can land until you mark it ready for review, on GitHub or with **Mark ready for review** in your Inbox. The per-repository toggle overrides the default either way. The exception is a pull request the workspace set to [auto-merge](/agent/approval#auto-merge-for-safe-changes): it opens ready for review.
* **The `attensira` label.** Every pull request we open carries it, without exception. It is a stable hook for a rule on your side — exclude the label from an auto-merge workflow, require an extra reviewer on it, or route it to a particular team.

<Note>
  We do not read your branch protection settings and cannot tell you what your automation will do with our pull request. If you are not sure, keep draft mode on, watch the first few, and turn it off once you are.
</Note>

## Lovable

If your site is built in [Lovable](https://lovable.dev), there is nothing separate to connect. A Lovable project can sync to a GitHub repository, and from then on a merge on the branch Lovable syncs shows up in the Lovable editor. So a fix reaches Lovable the same way it reaches any repository: as a pull request on that repository, which lands in Lovable when it is merged.

### Connecting

**Lovable** has its own card among your connectors (**Customize → Connectors**), but connecting it is the GitHub App install above: pick the repository your Lovable project syncs to, and attach it to the project. The card shows as connected once at least one attached repository syncs to Lovable. Disconnecting the Lovable card disconnects only those repositories; any other repository the project has stays connected.

### How we recognise a Lovable repository

When the repository is attached, we look for either of Lovable's own fingerprints on its default branch:

* `lovable-tagger` among the dependencies in `package.json`, which Lovable adds to every project it generates; or
* a README that links to `lovable.dev`, as the generated one does.

Either is enough. If neither is there, the repository is treated as an ordinary repository. If the files could not be read, nothing is decided: the repository works as an ordinary one, and we look again before the next pull request opens.

### What changes for a Lovable repository

The pull request itself is the same one any repository gets: a fresh branch, opened against your default branch, under the same [rules](#what-we-do-and-do-not-do). Two things are worded differently:

* **The pull request body** ends with: "Merging this lands it in your Lovable project if `<default branch>` is the branch Lovable syncs. Your live site changes when you next publish from Lovable."
* **Where it lives**, on [Deliverables](/agent/deliverables) and in `list_deliverables`, reads **Lands in Lovable after merge** while the pull request is open and **In Lovable** once it is merged. A pull request closed without merging landed nowhere, so it reads as the plain pull request it was.

<Warning>
  **Two things we cannot see.** We cannot read which branch your Lovable project syncs: if you switched Lovable to a branch other than the default, a merge into the default branch does not reach Lovable. And Lovable does not publish on a sync: a merged change is in the Lovable editor, and reaches your live site only when you publish from Lovable.
</Warning>

The [re-reads](/measure/before-and-after) are booked when the pull request merges, as for any repository, and we cannot tell whether you have published from Lovable since. Publish soon after you merge, so the first re-read, seven days later, measures a page that carries the change.

## Disconnecting

Disconnect from the project's GitHub settings, or uninstall the App from GitHub — either one ends our access immediately.

Pull requests we already opened **stay exactly as they are**. They are ordinary pull requests in your repository, owned by you: nothing is closed, withdrawn, or rewritten on the way out. What stops is everything future — no new branches, no new pull requests, and no further tracking, so the merged/closed and CI state on existing Inbox rows freezes at whatever it was when you disconnected.

Reconnecting starts the same install flow again. It does not resume tracking on pull requests opened before you disconnected.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.