Skip to main content
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 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 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.
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.

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 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:
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:
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 naming the file. Fix the .auto/ files and push a new commit; the plan re-runs automatically. Nothing was applied.
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.
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.

Everything that can start a sync

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

Where to go next

The resource model

What Sync compiles and applies: files, resources, plans, prune.

Managed templates

Specifiers, pinning vs @latest, overrides, and required variables.

Connections and identities

The GitHub connection behind the binding, and optional connections.

Variables and templating

The context variables Sync injects from the binding, like repoFullName.