Skip to Content

gtmesh upgrade

Re-applies the engine-owned scaffold files into your project, refreshing them to the current version without overwriting anything you’ve edited.

gtmesh upgrade [--dry-run] [--with-defaults]

What it does

A scaffolded mesh repo contains two kinds of files: engine-owned files (the plumbing init laid down and the engine maintains) and project-owned files (your config, reference data, per-type schemas, and templates). After you bump the gtmesh CLI itself, gtmesh upgrade brings the engine-owned files in your project up to the new version.

Every skill under .claude/skills/ is engine-owned, so upgrade keeps them current. A skill is a parameterized capability: you retune it by editing what it readsfoundation/voice.md, foundation/editorial.md, foundation/brand.md, templates/<page-type>.md, reference/editorial-rules.yaml, and the relevant gtmesh.config.yaml blocks — rather than by editing the skill. If you have edited one anyway, upgrade keeps your version and writes the new one beside it as SKILL.default.md to merge.

It’s careful about your work:

  • Engine-owned files are refreshed only if you haven’t touched them. If you have edited one, the new version lands beside it as <file>.default.<ext> for you to merge by hand — your edit is never clobbered.
  • Project-owned files (config, reference data, your per-type schemas, templates) are never overwritten. The one thing upgrade does to gtmesh.config.yaml is run its format migrations — structural edits that keep every value and comment you wrote.
  • It’s idempotent — running it again when you’re already current is a no-op.

Use --dry-run to see the plan first. Use --with-defaults to also drop the new project-file defaults next to yours (as *.default) so you can hand-merge any changed defaults.

How you learn an upgrade is due

You don’t have to remember to check. The mesh tells you, on what actually differs rather than on a version number — a release often ships no scaffold change at all, so a version comparison would nag you for a release that changed nothing of yours.

  • gtmesh doctor reports the whole picture as engine-files-pending: the files a plain gtmesh upgrade would take, and separately the ones that need a hand-merge (files you edited, and project-owned files whose engine default moved).
  • gtmesh status closes with a one-line footer counting the files a plain gtmesh upgrade would take. A file you’ve edited never reaches this footer — it resolves through a merge, not an upgrade, so nagging you about it on every command would be noise.
  • validate, seal and apply warn about exactly one file: schemas/common.schema.yaml, the shared base every per-type page schema $refs. When it’s pending, those commands validated against a stale contract — the one case where a missed upgrade changes an answer rather than just holding back an improvement.

A mesh that’s current prints none of this.

It restores its own baseline

upgrade compares your files against .gtmesh/manifest.json — the baseline init recorded, which is how it knows an engine file is untouched versus edited. That file is engine state, not one of your project files, so if it’s missing (an older project that predates it, or one where it was deleted) upgrade recreates it from the bundled scaffold and carries on, printing:

recreated .gtmesh/manifest.json (was missing — upgrade baseline restored)

apply does the same, and --dry-run heals too — the baseline is what the dry plan is computed from. Nothing of yours is touched by the heal; only the manifest is written. A directory with no gtmesh.config.yaml isn’t a gtmesh project, and there upgrade still stops rather than inventing a baseline.

It runs the schema migrations

Some engine upgrades change the shape of your committed state (a hash formula, a new field). upgrade reconciles that with a versioned, sequential migration chain — the same idea as a database schema migration.

Your mesh records the schema it’s on in graph/meta.json (a small, committed, machine-owned file: { "schema_version": N }). A mesh with no graph/meta.json is version 0. When you upgrade, the engine runs each migration step from your mesh’s version up to the current one, in order, then stamps the new version.

Two properties matter:

  • It catches up from any age. A mesh several versions behind runs the whole chain (v0 → vN) in a single upgrade — you never have to step through intermediate releases.
  • Each step fires exactly once. The version stamp gates every step, so re-running upgrade when you’re already current is a no-op — a migration never runs twice against the same mesh.

graph/meta.json is written by upgrade and committed — commit it along with the other changes so your teammates (and clones) know which schema the mesh is on. --dry-run runs no migrations.

It migrates your config file

gtmesh.config.yaml has its own chain, on the same pattern. Engine releases occasionally change the shape of the config — a key gets a clearer name, a setting the engine stopped reading gets dropped. upgrade makes that change for you rather than leaving you to find it in a changelog.

The version lives in the config itself, as a top-level config_version key:

# gtmesh.config.yaml — the ENGINE-FACING structural law for this mesh. # …your header comment… config_version: 1 project: my-mesh

A config with no config_version is version 0 — every mesh scaffolded before this existed — and the first upgrade brings it current and writes the stamp in as the first key, under your own header comment. Three things are worth knowing:

  • Your comments survive. The config is a file you read and annotate, so migrations edit it through the YAML tree rather than re-serializing it: every comment — the header block, the notes above a key, the inline trailers — and the key order come out the other side. Values are only ever touched by the specific step that moves them. YAML whitespace inside untouched blocks may be re-columned, so expect a slightly noisy diff the first time.
  • Nothing behaves differently. Config migrations are structural. Run gtmesh plan before and after and you get the same plan, down to its config_hash — the stamp itself is deliberately excluded from that fingerprint, so a migration never reads as “config changed since the last apply.”
  • It runs exactly once. The stamp gates every step, so a config already at the current version isn’t even rewritten — a second upgrade leaves it byte-identical, and upgrade says nothing about it.

When a migration does run, upgrade names the steps it applied:

migrated gtmesh.config.yaml v0 → v1 (ran: config-version-stamp); comments preserved — review the diff before committing

Review that diff like any other change and commit gtmesh.config.yaml with the rest of the upgrade. --dry-run runs no config migration either.

upgrade refreshes the files inside an existing project. Bumping the gtmesh CLI binary itself is a separate step — see the full workflow in Installation.

Arguments & flags

OptionDescriptionDefault
--dry-runReport the plan without writing anythingoff
--with-defaultsAlso write changed project-file defaults as *.default for hand-mergingoff

The global options (--project, --json, --quiet) also apply.

Reads & writes

  • Consumes: the bundled scaffold assets for the installed CLI version, compared against your project’s files.
  • Produces: refreshed engine-owned files; <file>.default.<ext> beside any engine file you’ve edited; and, with --with-defaults, *.default copies of changed project-file defaults. It also runs any pending schema migrations (updating your committed state and stamping graph/meta.json) and any pending config-format migrations (editing gtmesh.config.yaml in place and stamping its config_version). With --dry-run, produces only a plan — read-only.
  • Commits: review the refreshed files and merge any .default sidecars; commit them along with graph/meta.json, gtmesh.config.yaml, and any migrated state.

Examples

gtmesh upgrade --dry-run # preview what would change gtmesh upgrade # refresh engine-owned files in place gtmesh upgrade --with-defaults # also surface changed project-file defaults to hand-merge
  • Installation — the full upgrade workflow, including bumping the CLI itself.
  • Reference — the version-exact flag list.
Last updated on