/update-gaia
/update-gaia pulls the latest GAIA release into your project. It merges each file by comparing three versions: your file, the same file in the GAIA release your project is on, and the same file in the latest release (a three-way merge). GAIA’s changes come in, your customizations stay, and you answer one question per real conflict. When a new release is available, the statusline shows a 🚀 /update-gaia indicator.
It runs like every maintenance command: from the main checkout, in a worktree of its own, ending in a pull request.
How to invoke
Section titled “How to invoke”Click the 🚀 /update-gaia statusline indicator, or ask in plain language:
- “update GAIA”
- “pull the latest GAIA”
- “apply the new GAIA release”
What it does
Section titled “What it does”- Checks where it is running. Stops inside a linked worktree other than its own update worktree. Reads your current GAIA version from
.gaia/VERSIONand looks up the latest release. Never moves you to an older version. - Pulls first if your checkout is behind. When your main checkout’s GAIA version is behind the remote’s, it fast-forwards your checkout instead of updating, then offers to continue from the pulled copy.
- Checks whether a teammate is already updating. Each update run opens a draft pull request first to mark the update as in progress (step 7). Before any download, it looks for one. If a teammate’s update is still in progress, your run stops and names their pull request. If the open update is your own, the run resumes it or closes it to start fresh. The statusline also shows when a teammate’s update is in progress.
- Downloads and verifies the bundles. Each release ships as
gaia-bundle-<tag>.tar.gzwith a.sha256checksum file. The bundle for your current version and the latest bundle are both checked against their published checksums before anything else happens. On a mismatch nothing has changed yet: the bad download is deleted and the run stops and tells you. Run/update-gaiaagain for a fresh download. If that one still doesn’t match, the release is damaged or tampered with; report it to GAIA. - Picks the migration notes shipped in the verified bundle (see Migration notes).
- Shows the full changelog from your version to the latest, including every release in between, and asks Proceed or Abort. Abort leaves your project unchanged. The downloaded bundles are kept for the next run.
- Creates an update worktree on an
update/v<version>-<timestamp>branch, from the default branch, whichever branch your main checkout holds. Your checkout’s branch, files, andnode_modulesstay as you left them. The run then opens a draft pull request with an empty commit to mark the update as in progress, so two teammates never update at once. If it can’t open one, it warns and continues without it. - Merges every file (see The three-way merge), then asks you one question per real conflict, up to four per prompt. Every answer is recorded in
.gaia/update-decisions.json, which is committed with the update, so the next update does not ask again. An item you put off is asked again at the next update. - Follows after-merge migration notes and carries any new project-wide setup steps the release adds. New setup steps for this machine wait for the merge (step 12), because they act on your main checkout, not the update’s worktree.
- Writes the new version and manifest, runs the Quality Gate, and shows a summary: every file by outcome, every answer, every item still deferred, and any action the release notes say you owe (a dependency GAIA dropped, a file it removed), with the exact command. Those are suggestions; nothing is removed for you. Ask Claude to carry out any of them. It also records the harness files where it combined your edits with GAIA’s, so the statusline can suggest
/gaia-fitnessto review them once the update lands. - Asks once to commit, then pushes. The push updates the draft pull request from step 7, whose description is replaced with the summary; if there isn’t one, it opens a draft pull request,
chore(gaia): update to <tag>. Either way the pull request merges through the Code Audit Team. - Tells you what comes after the merge. When Claude merges the update’s pull request, it offers the leftover-file cleanup and runs the new setup steps for this machine in your main checkout. After a merge made elsewhere, such as on github.com, run
/setup-gaiafrom your main checkout to carry those setup steps.
The run ends with a cost line.
Why the checksum: a tampered or corrupted bundle would be merged straight into your Claude setup and hooks. See the gate reference.
The three-way merge
Section titled “The three-way merge”For every file GAIA ships, /update-gaia compares three copies:
- Yours: the file in your project now.
- Base: the same file in the GAIA release your project is on, the version in
.gaia/VERSION. - Latest: the same file in the new release.
The base is what makes the merge safe. Comparing yours with the base shows what you changed. Comparing the latest with the base shows what GAIA changed. So the merge never has to guess whose edit a difference is.
| What changed since the base | What happens |
|---|---|
| Only you changed the file, or nobody did | Yours stays as it is. |
| Only GAIA changed it | GAIA’s new version replaces yours. |
| You both changed it | The two sets of changes are merged, then checked by Claude (below). |
| The file is new in the release | It is added. |
| You deleted the file | It stays deleted. |
| GAIA removed the file, and you never edited it | It is deleted. |
| GAIA removed the file, and you edited it | You are asked whether to remove it or keep it. |
When you both changed a file, git merge-file merges the two line by line. Claude then reads your change and GAIA’s change side by side, even when the text merged cleanly. Two edits can solve the same problem on different lines and merge without a conflict into duplicate or contradictory instructions, which a line-by-line merge cannot see.
- Separate concerns that merged cleanly are written with no question.
- Everything else becomes one question: a text conflict, two changes to the same thing, or changes that contradict each other. The answers are Combine (both changes in one version, shown to you first), Keep mine, Take GAIA’s, and Decide later, with the recommended one first. When your change covers something GAIA’s misses, Claude suggests opening an issue on gaia-react/gaia (opens in a new tab) describing it.
Every file the merge overwrites or deletes is backed up first, under .gaia-backup/<timestamp>/ in the update worktree (gitignored).
How GAIA classes its files
Section titled “How GAIA classes its files”.gaia/manifest.json is GAIA’s list of the files it ships. It gives each file one of three classes, which decide the recommended answer when you and GAIA both changed it:
owned: GAIA maintains the file. Most of.claude/,.gaia/and.githooks/is owned. A conflict question recommends GAIA’s version. If you already had a file of your own at a path a new release starts shipping, yours is backed up and replaced.shared: GAIA ships a starting version that you are expected to customize, such asCLAUDE.md,.claude/settings.json,package.json,.gaia/audit-ci.yml,frontend/app/styles/theme.cssand the CI workflows. A conflict question recommends keeping yours. If you already had a file at a path a new release starts shipping, you are asked instead of overwritten.wiki-owned: pages inwiki/that GAIA ships. They merge likesharedfiles, and sections you added to one are kept.
What the merge never touches
Section titled “What the merge never touches”- Files GAIA does not ship. Anything not listed in
.gaia/manifest.jsonis yours. wiki/log.md,.gaia/VERSION,.gaia/manifest.jsonand.gaia/update-decisions.json. The update writes the last three itself..gaia/packages.json, the list of packages in your workspace. It is yours from the start..gaia/finding-classes.json, your project’s own audit finding classes. It ships empty and is yours from the start.- Your design system, once it is established. After you settle your project’s design (the
Design Systemwiki page is marked established), that page andfrontend/.claude/rules/design-baseline.mdbecome yours, and later updates skip both. frontend/.claude/settings.json. It is never merged. GAIA rebuilds it from the root.claude/settings.jsonplusfrontend/.claude/settings.overlay.json, so put frontend-only settings in the overlay.
package.json, pnpm-workspace.yaml and .gaia/audit-ci.yml are merged key by key instead of as whole files. A key only you added is never touched, and neither is a key you removed that GAIA later changed. A key GAIA changed that you left alone takes GAIA’s value. A key you both changed becomes a question. Your own dependencies, overrides, build approvals and Code Audit Team entries stay as you set them. Each Code Audit Team reviewer file has a section listing the files that reviewer covers; after the merge, GAIA rebuilds that section from your .gaia/audit-ci.yml, so it matches your project and not GAIA’s.
Leftover-file cleanup
Section titled “Leftover-file cleanup”GAIA keeps machine-local state under .gaia/local/, which is never committed. When a release retires a feature, the files that feature kept there are no longer used, and the leftover-file cleanup deletes them. Files it doesn’t recognize are listed and never deleted.
The cleanup can’t run inside the update’s worktree: it needs the new release’s list of retired files in your main checkout, which arrives only when the update’s pull request merges and your main checkout pulls it. So the cleanup runs after the merge. When Claude merges the update’s pull request, its cleanup step pulls your main checkout, lists the leftover files, and asks before deleting them. It then runs any new setup steps for this machine that the update held back.
If that pull was skipped or failed, Claude tells you so, and if you merged on github.com, nothing offers it. In either case, once your main checkout is pulled, start Claude there (not in a worktree: a worktree’s .gaia/local/ is only a link to the main checkout’s) and ask:
The GAIA update merged. Run GAIA's leftover-file cleanup from this main checkout, show me the list, then apply it if I agree.Then type /setup-gaia there to run the held-back setup steps for this machine.
Every machine has its own .gaia/local/, so each teammate’s copy has its own leftovers. A teammate who runs /update-gaia after the update merged gets the cleanup offered: the run pulls the update into their checkout (step 2), runs the new setup steps for their machine, shows the leftover files, and asks before deleting them. A teammate who pulled the update some other way can paste the same prompt.
Stopping and resuming
Section titled “Stopping and resuming”Every stop after the update worktree exists leaves it in place, changes nothing in your main checkout, and prints the worktree’s path.
Re-run /update-gaia to resume. If a run stopped before writing the new version, re-running safely repeats the merge and your answers. If it stopped after writing the version but before committing, re-run it inside the update worktree and it picks up at the Quality Gate.
To throw the stopped update away instead, ask Claude:
Discard the stopped GAIA update: close its draft pull request, then remove its worktree and branch.Migration notes
Section titled “Migration notes”A release can ship migration notes in its bundle, under .gaia/migrations/<version>.md, for steps a file merge cannot do: moving a directory tree, rewriting a config, removing a retired feature. /update-gaia reads notes only from the verified bundle, never from your working tree or a URL. It follows the notes for every version between yours and the latest, oldest first.
- After-merge notes run after the merge and before the version write. They are safe to repeat.
- Blocking notes stop the update before anything is branched or merged.
/update-gaianames the note and asks whether to follow it now. Following the note brings you to that note’s version; re-run/update-gaiaafterwards to get anything newer.
Gotchas
Section titled “Gotchas”-
Run it from the main checkout. Inside any other linked worktree it stops and tells you whether an update is pending; open Claude Code in the main checkout and run it there.
-
An update to the same version that is already applied but not committed is reported as such, never as “up to date”. Commit it, or start over by asking Claude:
Discard the uncommitted GAIA version change so I can run /update-gaia again.