Sphere Layout Sync
A generated go-sphere project keeps receiving upstream layout changes. This skill performs that merge without destroying project code, and without silently reverting layout fixes.
If schema_version is unknown to you, stop and report it. Do not guess the
lock format.
If there is no lock file, this is a legacy adoption — go to section 5 and do not start a normal sync.
1. Read the Contract
Read, in this order:
.sphere/layout.lock.json— which layout, which ref, which base revision.sphere/layout.json— ownership patterns for this layoutdocs/LAYOUT_CONTRACT.md— the authoritative protocolAGENTS.md— layout profile and extension seams
The project's own copies outrank this skill wherever they disagree.
Lock shape:
{
"schema_version": 1,
"name": "standard",
"repository": "https://github.com/go-sphere/sphere-layout.git",
"ref": "master",
"upstream_module": "github.com/go-sphere/sphere-layout",
"base_revision": "full-git-commit-sha"
}
Unknown JSON fields are forward-compatible — preserve them. Layout source repositories themselves contain no lock file; only generated projects do.
2. Ownership Classes Drive the Merge
Patterns in .sphere/layout.json are evaluated in this order, first match wins:
generated → layout_owned → mixed → default project_owned.
| Class | Sync action |
|---|---|
generated |
Ignore upstream contents entirely. Regenerate from the merged handwritten sources afterwards. |
layout_owned |
Apply the upstream change directly when the local copy still equals the recorded base. Otherwise three-way merge. |
mixed |
Always semantic three-way merge of base, local, and target. |
project_owned |
Never replace merely because upstream changed. |
Diffing generated files is wasted work at best and a source of bogus conflicts at worst. Exclude them before you compare.
3. Update Procedure
- Resolve. Read the contract and lock. Resolve the requested target
revision; with none specified, resolve the current commit of the recorded
ref. - Materialize. Check out the base and target upstream commits into separate temporary directories. Do not run their code merely to compute a diff.
- Normalize the module path. Rewrite both snapshots from
upstream_moduleto the project's current Go module path before comparing. Skipping this makes every import line look like a change and buries the real diff. - Merge by class. Ignore
generated. Leaveproject_ownedalone. Applylayout_owneddirectly only where local equals base, else three-way merge. Always semantically three-way mergemixed. - Resolve deletions and renames carefully. If a file is deleted or renamed both locally and upstream, settle ownership before recreating it. Never resolve a conflict by discarding project code.
- Regenerate and verify. Regenerate through the layout Makefile, then run
formatting, dependency checks, tests, lint, and build — typically
make gen/all,make check,make build. Review the complete diff. - Commit the lock last. Update
base_revisiononly after every conflict is resolved and verification succeeds. If blocked, leave the lock unchanged and report the affected paths.
Step 7 is the safety property: a lock that still points at the old base means "this sync did not finish", which is recoverable. A prematurely advanced lock loses that information permanently.
4. Failure Handling
Stop and report, rather than improvising, when:
schema_versionis unrecognized- The recorded
base_revisionis not reachable in the upstream repository - A
project_ownedfile would have to be overwritten to make the merge succeed - Generated output still drifts after a full regeneration
- Tests or build fail and the cause is a merge decision rather than a pre-existing issue
Report the affected paths and the decision you could not make. Leave the lock untouched.
5. Adopting a Legacy Project
A project created before the contract has no .sphere/. To adopt it:
- Inspect the project's earliest template commit.
- Compare its Git tree against commits from the likely upstream layout.
- Record a revision only when exactly one upstream tree matches.
- If there is no unique match, ask the user for the originating revision. Do not infer a convenient base — a wrong base silently corrupts every future three-way merge.
- Once confirmed, write the version-1 lock and follow the normal update flow.
Identifying the layout variant (standard / simple / bun / telegram) is part of this step; their trees differ substantially.
6. Layout Release Checklist
When the change is to a layout repository itself rather than a generated project:
- README capabilities and
make helpoutput are accurate -
.sphere/layout.jsonownership patterns do not overlap - All derived outputs regenerated after schema, proto, or Wire changes
-
make checkandmake buildpass from a clean checkout - Provider-specific dependencies exist only in provider-specific layouts
- Breaking template changes documented
- No database deletion migration is applied automatically to downstream apps
Reporting
State: layout variant and lock status; base and target revisions; per-class
summary of what was applied, merged, ignored, and left alone; every conflict and
how it was resolved; regeneration and verification commands run with results;
whether base_revision was advanced, and if not, why.