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

# GitHub pull requests

> Connect GitHub, map your site to content repositories, and open pull requests from action drafts. Merging marks the action live.

> [!NOTE]
>
> GitHub pull requests are available on every plan with content drafts. Content
> drafts are covered in [Content drafts](https://docs.devtune.ai/insights-actions/content-drafts.md).

If your docs, blog or marketing pages live as Markdown or MDX files in a GitHub
repository, DevTune can open a pull request from an action's content draft
instead of you copying the draft by hand. You review and merge it in GitHub,
under your repository's own review rules. DevTune never merges.

When the pull request is merged, the action is marked live and its
before/after window opens in [Results](https://docs.devtune.ai/insights-actions/outcomes.md).

If your docs are hosted on GitBook, see [GitBook change
requests](https://docs.devtune.ai/integrations/gitbook-change-requests.md).

## What DevTune can touch

DevTune connects through the **DevTune.ai** GitHub App. The app asks for:

* **Contents**: read and write
* **Pull requests**: read and write
* **Metadata**: read

GitHub grants contents write on every repository you select for the app.
DevTune uses it only to commit to its own branches, named
`devtune/action-` followed by eight characters, and to open pull requests from
them. It never commits to your other branches, never merges and never edits
code files. It writes only `.md` and `.mdx` files inside a content source's
folder.

Pages whose copy lives in a CMS or in code (React components, for example)
can't get a pull request.

## Connect GitHub

You need project management permission.

1. Open your project's **Settings** and select the **Integrations** tab.
2. Under **Content repositories**, select **Connect GitHub**.
3. In GitHub, choose the organization or user account and select the
   repositories that hold your content.
4. Approve the request. You return to DevTune, which shows **GitHub connected.
   Add a content source.**

The GitHub account appears under **Content repositories** as **Connected**.
DevTune lists only repositories you can push to through the app. To add a
repository later, add it to the app in GitHub, then select **Connect GitHub**
again to refresh the list.

If your repositories span several GitHub organizations, connect each one. Every
project in the DevTune account can use a connected GitHub account.

### If connecting fails

| Message | What to do |
| - | - |
| **Your GitHub organization owner needs to approve the DevTune app. Connect again once they have.** | Ask an owner of the GitHub organization to approve the install request, then select **Connect GitHub** again |
| **Your GitHub account cannot access that installation. Install the app on an organization you belong to.** | Sign in to GitHub as a member of the organization where the app is installed, or install it on your own organization |
| **Only account managers can connect GitHub.** | Ask an account manager to connect |
| **GitHub could not be connected. Try again.** | Select **Connect GitHub** again |

## Content sources

A content source maps a site address onto a place in a repository:

| Site address | Repository | Branch | Folder |
| - | - | - | - |
| `docs.example.com/` | `example/docs` | `main` | `/` |
| `example.com/blog/` | `example/www` | `main` | `content/blog` |

One repository can back several sources with different folders, which covers
monorepos.

To add a content source:

1. Under **Content repositories**, find **Add a content source**.
2. Enter the **Site address**, such as `docs.example.com` or
   `example.com/blog`. DevTune suggests addresses from your project's domains;
   select one to use it.
3. If you connected more than one GitHub account, choose the **GitHub
   account**.
4. Select the **Repository**.
5. Enter the **Branch**. Leave it empty to use the repository's default branch.
6. Enter the **Folder** that holds the pages. Leave it empty for the repository
   root.
7. Select **Add source**.

If adding a source fails, the form says why:

| Message | What to do |
| - | - |
| **Enter a site address such as docs.example.com or example.com/blog.** | Enter the address without `https://`, as a host and optional path |
| **Another source already covers that site address.** | Remove the other source first, or use a longer address under it |
| **The DevTune app cannot reach that repository. Add it to the app on GitHub.** | Add the repository to the DevTune.ai app in GitHub, then select **Connect GitHub** again |
| **That branch does not exist in the repository.** | Check the branch name, or leave it empty for the default branch |
| **That folder does not exist on the branch.** | Check the folder path on that branch, or leave it empty for the root |
| **Enter a folder inside the repository.** | Enter a path inside the repository, such as `content/blog`, with no `.` or `..` parts |

DevTune detects the format when you add the source. A `docs.json` or
`mint.json` in the folder marks it **Mintlify**; anything else is
**Markdown**. The format shows beside the repository, branch and folder.

A page belongs to the source with the longest matching site address. With
sources for `example.com/` and `example.com/blog/`, a page at
`example.com/blog/launch` uses the blog source. Each site address can belong to
only one source in a project.

To remove a source, select **Remove** beside it. Pages under that address can
no longer get pull requests. Open pull requests stay open in GitHub.

## Open a pull request from a draft

You need project management permission.

1. Open an action with a content draft.
2. In the **Draft** section, select **Create pull request** beside **Download
   markdown**.

DevTune opens the pull request for the latest draft version and links it as
**Pull request #** with its number and state. Each action has one pull request
at a time.

**Refresh actions.** DevTune finds the page's file in the source's folder from
its URL: `<path>.mdx`, `<path>.md`, `<path>/index.mdx`, then `<path>/index.md`.
For a Mintlify source, it also checks the navigation in `docs.json` or
`mint.json`. It applies every section edit to that file. If any change does not
match the file, nothing is written.

**Create actions.** DevTune writes a new file named from the brief's target
page: `.mdx` for Mintlify and `.md` for Markdown. Mintlify files get `title`
frontmatter, plus a `description` taken from the draft's first paragraph when
it has one. Markdown files get `title` only. If the brief's
target is not under any content source, choose a **Content source** and select
**Try again**.

The pull request's title is the action's title. Its description links the
action and lists the brief's acceptance criteria under **Done when** and any
facts the fact check still flags under **Facts to verify**. For a new page, it
lists what to do **Before merging**.

DevTune does not open a pull request for a [locked
page](https://docs.devtune.ai/insights-actions/actions-hub.md#locked-pages).

### Update a pull request

After you select **Generate new draft**, the Draft section shows **The newest
draft is not in this pull request yet.** Select **Update pull request** to push
the new version to the same pull request. DevTune applies it to the file as it
is on your branch, as a new commit on its own branch.

If someone else has pushed to DevTune's branch, DevTune leaves their commits
alone and refuses the update. Make further changes in GitHub.

### Close a pull request

Select **Close pull request** and confirm. DevTune closes the pull request in
GitHub and deletes its branch, unless someone else has pushed to it. The draft
stays in DevTune, and you can create a new pull request.

You can close a pull request even after your plan no longer includes GitHub
pull requests, or after you remove its content source.

## Automatic pull requests

Turn on **Open pull requests automatically** beside a content source. It is off
by default.

When it is on, each new content draft for a page under that source opens the
action's pull request, or pushes the draft to its open one. The pull request
opens as the member who started the draft run, so merging it marks the action
live as that member. That member still needs project management permission when
the draft finishes; otherwise no pull request opens.

If DevTune can't open an automatic pull request for a page it has found a
source for, the reason shows in the action's **Draft** section, with the fix
from [Refusals](#refusals). If the action already has an open pull request and
the new draft can't be pushed to it, the Draft section shows **The newest draft
is not in this pull request yet.** Select **Update pull request** to retry. If it fails again, the reason appears there.
If the member who started the run no longer has project management permission,
no pull request opens and nothing is shown; create it yourself from the Draft
section.

## Merge and close in GitHub

* **Merged.** The action is marked live with the page's published URL, and its
  before/after window opens in [Results](https://docs.devtune.ai/insights-actions/outcomes.md). An
  action that was still a suggestion is accepted first. A refresh
  action uses its own page URL. A new page uses the URL its file serves under
  the source's site address. DevTune marks it live as whoever opened the pull
  request. If that member or API key can no longer manage the action, select
  **Mark live** on the action yourself.
* **Closed without merging.** The pull request is recorded as **Closed**. The
  action is unchanged, and you can create a new pull request.

## What to expect in your repository

* **Preview builds.** If your repository builds previews for branches, as
  Vercel, Netlify and other Git integrations do by default, each push to
  DevTune's branch starts one. Use the preview to check the page before
  merging.
* **Navigation.** DevTune does not edit site navigation (`docs.json`, sidebars
  or menus). Add a new page to your site's navigation in the pull request
  before merging.
* **Frontmatter.** For a new page in a Markdown source, complete the
  frontmatter your site's framework needs. DevTune adds `title` only.
* **MDX.** In `.mdx` files, DevTune escapes `<` and `{` in the text it writes,
  outside code, so the page builds.

## Disconnect and reconnect

A content source shows **Reconnect needed** when:

* The app is suspended in GitHub. The GitHub account shows **Suspended on
  GitHub**. Unsuspend the app in GitHub to restore its sources.
* The app is uninstalled in GitHub. Select **Connect GitHub** and install it
  again.
* The source's repository is removed from the app. Add the repository back to
  the app in GitHub.

While a source needs reconnecting, its pull requests can't be created, updated
or closed from DevTune. Close them in GitHub if you need to.

To disconnect, select **Disconnect** beside the GitHub account and confirm.
Every content source on that GitHub account is removed. Open pull requests
stay open in GitHub. Disconnecting does not uninstall the app; uninstall it in
GitHub to remove its access to your repositories.

## Refusals

When DevTune can't create, update or close a pull request, the Draft section
shows why.

| Message | Fix |
| - | - |
| **Content pull requests are not available on this account.** | Your plan has no content drafts. Check your plan on **Billing** |
| **This action no longer exists.** | Reload the Actions queue |
| **Generate a draft first.** | Select **Generate draft** in the Draft section |
| **A newer draft replaced this one. Reload the page.** | Reload the page and review the newest draft before creating the pull request |
| **Live and archived actions take no pull requests.** | Only open actions get pull requests |
| **This page is locked, so DevTune does not change it.** | Unlock the page in **Settings › Pages** if you want DevTune to edit it |
| **No content source covers this page. Select one.** | Choose a **Content source** and select **Try again**, or add a source for the page's site address in **Settings** |
| **Reconnect GitHub in project settings, then try again.** | Follow [Disconnect and reconnect](#disconnect-and-reconnect) |
| **Enter a .md or .mdx file inside the content source's folder.** | Enter a **File path** to a `.md` or `.mdx` file inside the source's folder |
| **No file for this page was found. Enter its file path.** | Enter the page's **File path** in the repository and select **Try again** |
| **That file already exists. Enter another file path.** | Enter a **File path** that does not exist yet and select **Try again** |
| **Changes 2, 5 do not match the file. Generate a new draft, then try again.** | The file changed since the draft was written. Select **Generate new draft**, then create the pull request again |
| **The draft does not match the file. Generate a new draft, then try again.** | Select **Generate new draft**, then create the pull request again |
| **Someone else pushed to DevTune's branch. Update the pull request in GitHub.** | If the pull request is open, make further changes in GitHub. If it is closed, delete the `devtune/action-` branch in GitHub, then try again |
| **A pull request is already being opened. Try again in a minute.** | Wait a minute and try again |
| **This pull request was merged. Mark the action live.** | Reload the page. If the action is not live, select **Mark live** |
| **This action has no open pull request.** | Reload the page |
| **GitHub refused the request. Try again.** | Try again. If it keeps failing, check the app still has access to the repository in GitHub |

## API and MCP

Your own agents can do the same with an API key or MCP connection created by a
member with project management permission. Creating, updating and closing
pull requests needs `actions.write`; reading the draft and its pull request
needs `actions.read`:

* **API.** `POST /api/v2/projects/{projectId}/actions/{actionId}/draft/pull-request`
  creates or updates the pull request, and `DELETE` on the same path closes it.
  `GET /api/v2/projects/{projectId}/actions/{actionId}/draft` returns the pull
  request with the draft. `GET /api/v2/projects/{projectId}/setup/content-sources`
  lists the project's content sources and needs `setup.read`. See [Create
  action draft pull request](https://docs.devtune.ai/api-reference/create-action-draft-pull-request.md),
  [Close action draft pull
  request](https://docs.devtune.ai/api-reference/close-action-draft-pull-request.md) and [List content
  sources](https://docs.devtune.ai/api-reference/list-content-sources.md).
* **MCP.** `devtune_create_draft_pull_request`,
  `devtune_close_draft_pull_request` and `devtune_get_content_sources`. See
  [MCP server](https://docs.devtune.ai/api-reference/mcp-server.md).

Content sources are added and removed in the app.

## Next steps

* [Generate content drafts](https://docs.devtune.ai/insights-actions/content-drafts.md)
* [Measure shipped actions in Results](https://docs.devtune.ai/insights-actions/outcomes.md)
* [Create API keys](https://docs.devtune.ai/account-billing/api-keys.md)


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