.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, inowner/nameform, 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.
.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 markedoptional: truewhose 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.
.auto/ file is skipped entirely — no check, no comment.
What happens after merge
A push to the production branch (a merge, or a direct push) starts the apply:- 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. - A check named Sync apply goes
in_progresson the merge commit (“Applying Sync”). - The worker reads the full
.auto/tree at the merge commit, compiles it, and runs the real apply with prune enabled. - 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. - 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 iskind/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— theconfig/projectsingleton is archived, like any other resource.
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.
@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:
Reading a failed sync
Sync failures are loud in exactly one place each, and nothing is lost:A pull request plan failed
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 naming the file. Fix the .auto/ files and push a new commit; the plan re-runs automatically. Nothing was applied.A merge applied, but the apply failed
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.Where to look for detail
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.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.