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

# GitHub

> Connect GitHub so Nota can read and file issues, and wire issue events, @nota mentions, and pull-request content back into Nota.

## Summary

This page explains the GitHub integration at a glance and the two integration directions:

* **Outbound (Nota → GitHub):** Nota uses a GitHub access token to list issues and file new issues from workflow runs.
* **Inbound (GitHub → Nota):** GitHub sends webhook events — new issues trigger coverage discovery, `@nota` mentions in issue and pull-request comments get an in-thread reply, and pull-request content is ingested as context.

Includes the required token permissions, a setup checklist, testing steps, and common troubleshooting scenarios.

# 🐙 GitHub (team feature)

Connecting GitHub has two directions:

* **Outbound** (Nota → GitHub) — Nota lists issues and files new ones. Needs an access token.
* **Inbound** (GitHub → Nota) — new issues kick off coverage discovery, `@nota` mentions get an in-thread reply, and pull-request content is ingested. Needs a webhook, and (for mentions) a dedicated Nota account.

**Set up outbound first.** Inbound routing depends on a value Nota resolves when you save the outbound token — see Outbound Step 2.

<Note>
  For the full experience — where replies post **as Nota** and teammates can `@`-mention it — create the **dedicated Nota account** in the Inbound section first, then generate the outbound token *from that account*. GitHub attributes every API action to whichever account owns the token.
</Note>

***

# Outbound — let Nota act on your repositories

<Warning>
  **From chat, GitHub is create-only.** Nota can **list** issues and **create** new ones. There is no chat tool to comment on, assign, close, label, or otherwise update an existing GitHub issue or pull request. Ask for one of those and Nota hands off explicitly rather than quietly filing a new issue instead. If you need full write access from chat, use Linear, Jira, or GitLab.

  (Inbound `@nota` mention replies *do* post a comment — that's the reply path Nota owns, not a chat tool you can point at an arbitrary thread.)
</Warning>

## Step 1 — Create the GitHub access token

1. On [github.com](https://github.com), click your **profile photo** (top-right) → **Settings**.

2. In the left sidebar, scroll to **Developer settings** → **Personal access tokens** → **Fine-grained tokens**.

3. Click **Generate new token**, name it, and set an expiry.

4. Under **Repository access**, pick the repositories Nota should work with (or **All repositories**).

5. Under **Permissions → Repository permissions**, grant:

   | Permission        | Level          | Why                                                                                                                       |
   | ----------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------- |
   | **Issues**        | Read and write | List issues, file new issues, and post `@nota` replies — GitHub delivers pull-request comments through the issues API too |
   | **Pull requests** | Read-only      | Ingest pull-request metadata and diffs when a PR opens or updates                                                         |
   | **Metadata**      | Read-only      | Mandatory — GitHub selects it automatically as soon as you grant any repository permission                                |

6. Click **Generate token**, then **copy and save it** — GitHub shows it only once. This is your **GitHub Access Token**.

<Note>
  A **classic** token with the `repo` scope also authenticates, but `repo` grants far more than Nota needs (full read/write on code, not just issues). Prefer a fine-grained token scoped to the repositories you actually want covered.
</Note>

## Step 2 — Pick the default repository

<Warning>
  **The field is labelled optional, but inbound webhooks need it.**

  On save, Nota calls `GET /repos/{owner}/{repo}` with your token and stores the repository's canonical **GitHub Owner** login. That owner is what routes inbound webhook deliveries to your team.

  If no default repository is set — or the token can't read it — the owner never resolves and **every GitHub webhook is rejected as an unregistered workspace** (see Troubleshooting). Outbound still works fine without it; chat supplies a repository per request.
</Warning>

Enter it as **`owner/repo`** exactly as it appears in the GitHub URL:

* ✅ `my-org/my-repo`
* ❌ `https://github.com/my-org/my-repo` (no host)
* ❌ `/my-org/my-repo` (no leading slash)
* ❌ `my-repo` (owner is required)

Casing doesn't matter — Nota stores GitHub's canonical casing from the API response, so a mixed-case entry can't desync from inbound deliveries. The token **must be able to read that repository**; the same API call is what validates it.

## Step 3 — Configure Nota

Go to [app.trynota.ai/integrations](https://app.trynota.ai/integrations) and click **GitHub Settings**. Fill in:

| Field                   | Value                                                               |
| ----------------------- | ------------------------------------------------------------------- |
| **GitHub Access Token** | The token you saved in Step 1                                       |
| **Default Repository**  | The `owner/repo` from Step 2 — required for inbound webhook routing |

Click **Update Settings** — Nota uses it immediately, no redeploy needed. On save Nota also resolves and stores your **GitHub Owner** automatically; that's what routes inbound webhooks to your team later.

Leave **GitHub Webhook Secret** and **Nota Bot Username** blank for now — they're covered in the Inbound section.

<Check>
  **You're done with outbound.** In Nota chat, say **"list my open GitHub issues"** — you should see your issues. Then try **"file a GitHub issue for the last failing run"** — it should create one and hand you the URL.
</Check>

***

# Inbound — issue events, @nota mentions & PR content

## Step 1 — Create a dedicated Nota account

Only needed for **`@nota` mention replies**. Skip it if you just want new-issue discovery and pull-request ingestion.

1. Create (or reuse) an email for the bot, e.g. `nota@<your-domain>`.
2. Sign up a GitHub account with it and note its **username** — the exact text after `@` when you mention it (if the `@`-menu shows `@nota-bot`, the username is `nota-bot`).
3. Invite that account to your organization / repositories with at least **write** access so it can post comments.

<Note>
  Replies post using the **outbound access token**, so they're attributed to whichever account owns that token. For replies to appear as **Nota**, generate the fine-grained token from the bot account (Outbound Step 1) rather than from your own.
</Note>

## Step 2 — Generate a webhook secret

Generate a high-entropy secret and **save it** — you'll paste the same value into GitHub (Step 3) and Nota (Step 4):

```bash theme={null}
openssl rand -hex 32
```

GitHub signs every delivery with HMAC-SHA256 over this secret and sends the digest in the `X-Hub-Signature-256` header; Nota verifies against the copy you store. On the hosted app it's **required** — without it, deliveries are rejected.

## Step 3 — Create the webhook in GitHub

Go to your **repository → Settings → Webhooks → Add webhook** (or **Organization settings → Webhooks** to cover every repo at once), then:

| Field                | Value                                        |
| -------------------- | -------------------------------------------- |
| **Payload URL**      | `https://app.trynota.ai/api/webhooks/github` |
| **Content type**     | `application/json`                           |
| **Secret**           | The `openssl` secret from Step 2             |
| **SSL verification** | Enable                                       |

<Warning>
  **Content type must be `application/json`.** The `application/x-www-form-urlencoded` option wraps the whole event inside a `payload=` form field, which Nota's parser rejects — every delivery fails.
</Warning>

Under **Which events would you like to trigger this webhook?**, choose **Let me select individual events** and enable:

| Event                | Why                                                                       |
| -------------------- | ------------------------------------------------------------------------- |
| ✅ **Issues**         | New issue opened → Nota discovers test coverage                           |
| ✅ **Issue comments** | `@nota` mention in an issue **or pull-request** comment → in-thread reply |
| ✅ **Pull requests**  | PR opened / updated / merged → content ingested as context                |

Click **Add webhook**.

<Note>
  Unlike Linear — which generates a signing secret for you at webhook creation — **you supply this secret**, the same way GitLab's **Secret token** works. GitHub differs from GitLab in one respect: it signs the request *body* (HMAC-SHA256) rather than echoing the raw secret back in a header.
</Note>

## Step 4 — Configure Nota

Back in [app.trynota.ai/integrations](https://app.trynota.ai/integrations) → **GitHub Settings**, fill in:

| Field                              | Value                                                                                                                                   |
| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **GitHub Webhook Secret**          | The `openssl` secret from Step 2 (same value as the webhook)                                                                            |
| **Nota Bot Username** *(optional)* | The bot's GitHub username **without** the leading `@`, e.g. `nota-bot`. **Required for mention replies** — leave blank to disable them. |

Click **Update Settings**.

## Step 5 — Test it

<Check>
  **Mention Nota from a *different* account.** As **yourself** (not the Nota account), open an issue or pull request, add a comment, and type the bot's username — **`@nota-bot what does this issue cover?`**. Post it — Nota replies in-thread within a few seconds.

  The mention is matched case-insensitively (`@Nota-Bot` works), and the `@` must be followed by the exact username — a longer handle like `@nota-bot-staging` is **not** treated as a mention of `nota-bot`.
</Check>

<Check>
  **Open a new issue.** Nota picks it up and starts discovering test coverage for the surface the issue describes.
</Check>

<Warning>
  **Mention the bot from a human account, not as the bot.** The **loop guard** drops any comment whose author *is* the Nota account, so if you configure your own username and mention yourself, Nota stays silent by design (it must never reply to itself). Use the dedicated bot account's username and mention it from your normal account.
</Warning>

<Check>
  Comment **edits and deletions are ignored** — only newly-created comments trigger a reply. Post a fresh comment rather than editing an existing one.
</Check>

<Note>
  GitHub logs every delivery under **Settings → Webhooks → your webhook → Recent Deliveries**. Expand one to see the exact request and Nota's response — a `202` means Nota accepted and queued the event.
</Note>

***

## What each inbound event does

| Event                                                                                                       | Nota's response                                                 |
| ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Issue **opened**                                                                                            | Discovers test coverage for the surface the issue describes     |
| Issue comment **created**, containing `@<bot>`                                                              | Replies in-thread                                               |
| Pull request **opened / reopened / synchronized / edited / closed / ready for review / converted to draft** | Metadata and diff ingested as context — **no run is triggered** |

<Note>
  **Pull-request events are ingest-only.** Nota stores the PR's metadata and diff so later questions and runs have that context, but a pull request never starts a workflow run on its own. Metadata-only PR activity — labels, assignees, review requests, milestones — is ignored entirely.
</Note>

***

## Troubleshooting

| Result                                                           | Cause                                                                                                | Fix                                                                                                        |
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| Every delivery returns **200** `unregistered_platform_workspace` | **GitHub Owner** never resolved — no **Default Repository**, or the token can't read it              | Set a valid `owner/repo` your token can read (**Outbound Step 2**) and re-save; the owner resolves on save |
| Webhook **403** signature rejected                               | The **GitHub Webhook Secret** in Nota doesn't match the webhook's                                    | Re-copy the secret from the GitHub webhook into Nota (or regenerate both)                                  |
| Webhook **503** `integration not configured`                     | No signing secret stored in Nota and no platform-wide secret                                         | Complete **Inbound Step 4**                                                                                |
| Every delivery fails to parse                                    | Webhook **Content type** is `x-www-form-urlencoded`                                                  | Change it to `application/json`                                                                            |
| Mention posts but **no reply**                                   | Mentioned Nota **as** the Nota account → dropped by the loop guard                                   | Mention it from a *different* account                                                                      |
| Comment ignored (no detection)                                   | **Nota Bot Username** blank/wrong, or you mentioned a different username                             | Set the bot's exact GitHub login (no `@`); mention *that* username                                         |
| Reply fails to post                                              | The access token lacks **Issues: Read and write**, or the bot account lacks write access to the repo | Re-scope the token; grant the bot account write access                                                     |
| Issue create fails **404 / not found**                           | The token's **Repository access** doesn't include that repository                                    | Widen repository access on the fine-grained token                                                          |
| Saving settings rejects the repository                           | **Default Repository** isn't a bare `owner/repo`                                                     | Remove the host, leading slash, or trailing path — enter `my-org/my-repo`                                  |
| Chat says it can't comment on / assign / close a GitHub issue    | Expected — GitHub is create-only from chat                                                           | File a new issue instead, or use Linear / Jira / GitLab for full write                                     |
| Nothing happens when a PR opens                                  | Expected — PR events are ingest-only, they never start a run                                         | Trigger runs from chat, a schedule, or a new issue                                                         |

<Tip>
  Quick isolation: GitHub's **Recent Deliveries** tab shows the exact request and Nota's response for every event — a `403` points at the secret, a `200 unregistered_platform_workspace` points at the Default Repository. Treat the access token and webhook secret like passwords, and rotate them if you suspect either has leaked.
</Tip>
