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

# GitHub Sync

> CI/CD for your agents: plan .auto/ changes on every pull request, apply them on merge, and keep managed templates current automatically.

GitHub Sync makes a repository the source of truth for a project's resources. Open a pull request that touches `.auto/` and Sync posts the exact plan of what merging will change; merge it and Sync applies that plan. This page explains the binding, the checks and comments Sync writes, how deletes and renames reconcile, the template subscription sweep, and how to read a failed sync.

## The binding

A Sync **binding** ties one repository and branch to one auto project:

* `repo` — the repository, in `owner/name` form, reached through a GitHub connection (a GitHub App installation grant).
* `branch` — the **production branch**. Only merges to this branch apply resources; only PRs targeting it get plans.
* The synced path is always **`.auto/` at the repository root**. It is not configurable.

You create the binding from the project's repository settings in the web app, by choosing the configuration repository and its production branch through a GitHub connection.

If the repository already contains a `.auto/` directory when the binding is created — for example, a forked template repo — Sync immediately runs a full-tree "attach" apply of the production branch head, so pre-authored resources go live without waiting for the next push.

A binding can also carry an optional **CI watchdog** — up to 10 GitHub Actions workflow ids, plus a check delay (default 15,000 ms) — that Sync re-dispatches when a PR head is missing its CI run.

## The sync check on pull requests

Every pull request that targets the production branch and changes anything under `.auto/` gets a check named **Sync plan** plus a sticky PR comment. The plan is not a lint — it is a full [dry-run apply](/concepts/resource-model#dry-runs) of the PR's head commit through the same compile-and-plan path the merge will use. The only difference between the plan and the eventual apply is the `dryRun` flag, so a green plan is a faithful preview and a red plan is the same failure the merge would hit.

The comment is headed `Sync plan — N changes` (or `— no changes`) and groups changes by action and resource kind — **Created / Updated / Deleted** agents, environments, identities, and config — with per-field diff lines linked to the exact file and line at the head commit. A trailer carries the unchanged-resource count, the short head SHA, and a `sync details` link to the check run.

Plans can carry callouts:

* A `[!WARNING]` block when the plan completed with non-informational diagnostics.
* A `[!NOTE]` block listing skipped optional connections: "Optional connections are not active yet; set them up and re-sync to enable these." A tool or trigger marked `optional: true` whose [connection](/concepts/connections-and-identities) has no active grant is skipped rather than failing the apply, and re-activates on a later sync once the connection exists.
* A second `[!NOTE]` block for other informational diagnostics, such as the template bump advisories below.

A pull request that touches no `.auto/` file is skipped entirely — no check, no comment.

<Tip>
  Push a new commit to re-plan. The plan re-runs automatically on every head; each run is idempotent per `(binding, PR, head SHA)`, so duplicate webhook deliveries never double-apply.
</Tip>

## What happens after merge

A push to the production branch (a merge, or a direct push) starts the apply:

1. Sync lists what changed under `.auto/` since the **last successfully applied commit** — not just since the previous branch tip. If a prior apply was skipped or failed, its changes accumulate into this diff, so nothing is ever silently dropped.
2. A check named **Sync apply** goes `in_progress` on the merge commit ("Applying Sync").
3. The worker reads the full `.auto/` tree at the merge commit, compiles it, and runs the real apply with prune enabled.
4. On success, the check concludes with a summary — `Sync apply changed N resource(s). Create: … Update: … Archive: … Unchanged: …` — and Sync records the commit as the new applied high-water mark.
5. Sync then finds the merged PR and flips its plan comment to the applied outcome, `Sync applied — N changes`, so the PR itself shows that the reviewed plan actually landed. A direct push with no associated PR skips this step.

## How deletes and renames reconcile

A production-branch apply always prunes: any resource the project has that the compiled `.auto/` tree no longer declares is **archived**. That gives files ordinary git semantics:

* **Delete a file** — its resources are archived. The plan and apply comments render these under **Deleted**.
* **Rename a resource** (change its `name:`) — resource identity is `kind/name`, so this plans as a create of the new name plus an archive of the old one.
* **Rename or move a file** without changing resource names — no change. Identity comes from the compiled resources, not from file paths.
* **Remove `.auto/config.yaml`** — the `config/project` singleton is archived, like any other resource.

You review deletions the same way you review everything else: they appear in the PR's Sync plan before you merge.

## Template subscriptions and the sweep

Agents that import a [managed template](/reference/managed-templates) at `@latest` (or with no version, which means `@latest`) are **subscribed** to it. Each successful production-branch apply records, per template, the version that resolved. From then on:

* A background sweep runs every 5 minutes over subscriptions (up to 50 per cycle, rotating fairly through the full set). For any project whose recorded version lags the registry's current `@latest`, it dispatches a **template push** — a synthetic sync run per enabled binding that re-applies the production branch's current HEAD with the new template content. Your `.auto/` files are unchanged; only the resolved template bundle moves.
* Projects with no Sync binding are skipped; a project applied outside Sync picks up new template versions on its next apply.
* When a merge drops a template import, the next successful production-branch apply prunes that subscription, and the sweep stops pushing it.

Pinning a version (`@auto/code-review@1.2.0/...`) opts that import out of the sweep: pinned content never changes underneath you, and updates only arrive when you edit the pin.

When a push apply lands a template version bump, the Sync check and comment can carry two non-blocking advisories, attributed to the importing agent:

* **`template_capability_expanded`** — the new version added files to its bundle: "Review the new capabilities and set up any connections they require."
* **`template_override_outdated`** — your project overrides a template file (a file in your repo occupies the same path the template injects) that changed in the new version: your copy is kept, so reconcile it manually to pick up the update.

## Staleness advisories

The template registry is compiled into the deployed worker, so for a short window after a new template version merges, `@latest` still resolves to the previous version. This only matters for repositories that publish templates themselves; ordinary consumer repos never see it. When Sync detects the window — the commit declares a template version newer than the worker's registry, for a template consumed at `@latest` — the apply **proceeds with the deployed (previous) version** and adds an advisory naming both versions, appended to the check summary and rendered as a `[!NOTE]` callout on the comment:

```text theme={null}
- @auto/pr-review: applied v1.4.0; v1.5.0 reconciles after the worker redeploys
```

The subscription sweep reconciles to the new version automatically after the deploy. Detection fails open: if the source can't be read, there is no advisory and no blocked merge.

## Reading a failed sync

Sync failures are loud in exactly one place each, and nothing is lost:

<AccordionGroup>
  <Accordion title="A pull request plan failed">
    The **Sync plan** check concludes `failure` with the error as its summary, and the PR comment becomes **Sync plan failed** with the same message — typically a [validation diagnostic](/concepts/resource-model#validation-diagnostics) naming the file. Fix the `.auto/` files and push a new commit; the plan re-runs automatically. Nothing was applied.
  </Accordion>

  <Accordion title="A merge applied, but the apply failed">
    This is the loudest case: a reviewer saw a ready plan, the PR merged, and the resources did not change. The **Sync apply** check on the merge commit concludes `failure`, and the merged PR's comment flips to **Sync apply failed**: "This PR merged, but applying its `.auto/` changes failed. Resources keep their previously applied state until a push to the production branch syncs successfully."

    Recovery is a new push to the production branch — a fix-forward commit, or any later merge. Because pushes diff against the last *successfully applied* commit, the next successful apply covers the failed merge's changes too.
  </Accordion>

  <Accordion title="Where to look for detail">
    Every check and comment trailer links `sync details` to the check run, whose text carries the full grouped plan and diagnostics. Push and PR syncs run a single attempt each — a new commit or a check re-run is the retry. The one exception is connection-driven re-applies (below), which retry on a backoff for about an hour because they can race a platform deploy.
  </Accordion>
</AccordionGroup>

## Everything that can start a sync

For completeness, four inputs start a sync run, all idempotent per target:

| Input           | Trigger                                                                        | Result                                                                  |
| --------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| Pull request    | PR opened or updated against the production branch with `.auto/` changes       | **Sync plan** check + plan comment (dry run)                            |
| Push            | Merge or direct push to the production branch with `.auto/` changes            | **Sync apply** check + applied resources                                |
| Template push   | The subscription sweep detects a template `@latest` version bump               | Re-apply of the production HEAD with the new template content           |
| Connection push | A connection lifecycle change (for example, a provider grant added or removed) | Re-apply at the same commit so connection-dependent resources reconcile |

## Where to go next

<CardGroup cols={2}>
  <Card title="The resource model" href="/concepts/resource-model">
    What Sync compiles and applies: files, resources, plans, prune.
  </Card>

  <Card title="Managed templates" href="/reference/managed-templates">
    Specifiers, pinning vs @latest, overrides, and required variables.
  </Card>

  <Card title="Connections and identities" href="/concepts/connections-and-identities">
    The GitHub connection behind the binding, and optional connections.
  </Card>

  <Card title="Variables and templating" href="/reference/variables-and-templating">
    The context variables Sync injects from the binding, like repoFullName.
  </Card>
</CardGroup>
