Stability

Upgrading a project

A scaffolder gives you code once and then watches it rot. Grit keeps fixing the project it generated: grit upgrade brings an existing app up to the current templates, and it knows which files you have edited, so it never overwrites your work to do it.

The two commands people confuse

grit update # updates the CLI binary on your machine
grit upgrade # run inside a project: brings THAT project up to the CLI's version

They are different commands and the error from using the wrong one is confusing, so it is worth reading twice. grit upgrade is the one that touches your code.

It knows what you have edited

Grit records a hash of every file it writes, in .grit/manifest.json. That gives three answers for any generated file, and they lead to three different behaviours:

  • unchanged: the bytes on disk are the bytes Grit wrote, so it is safe to replace. It gets the new version.
  • modified: you have edited it. The upgrade reports a conflict and leaves your file alone. Nothing you wrote is lost by running this command.
  • untracked: Grit never wrote it. It is yours and is not touched.

That is why the manifest exists, and it is also why an agent working in your project should read it before proposing an edit: changing a pristine file is the moment that file stops receiving framework fixes. grit mcp exposes it as grit_file_ownership.

grit upgrade --diff # show what it would change in the files it leaves alone
grit upgrade # do it
grit upgrade --force # overwrite everything, including your edits

The files you own, that Grit also writes into

Some files are genuinely shared. routes.go carries your routes and Grit's, main.go wires your services and Grit's, config.go holds your settings and Grit's. Replacing those would throw away your application; leaving them alone would mean a framework fix never reaches the file where it matters.

So the upgrade carries 53 repairs. A repair finds the exact text Grit wrote, replaces it with the exact text Grit writes today, and when the text is not what Grit wrote, says so and changes nothing:

✓ apps/api/internal/routes/routes.go: /api/health answers ok, degraded, off or
unknown per component, reports storage, and merges anything health.Register was given
⚠ the verification email is not sent the way Grit wrote it: send it with dispatchMail
rather than from a `go` statement, so it is queued, retried and survives a restart

The warning is the interesting half. Grit found code it did not write, so it did not touch it, and it told you what the fix would have been and why. You can take it or leave it.

An upgraded project is a fresh oneEach repair is tested against the file the previous release actually wrote, and the assertion is that the result is byte-for-byte what a fresh scaffold produces today. An upgraded project that differs from a new one by a blank line is a diff somebody has to read on every later upgrade.

What travels, and why that is a decision

Two sets of files are rewritten on every upgrade rather than only at scaffold time:

  • Framework-owned code: the webhook cluster, feature flags, the permission engine, the audit services, the health package. Nothing describes them in a resource definition and they only make sense as a set. A fix to one that did not reach existing projects would be a fix for new projects only.
  • The codegen runtime: the packages generated code imports, such as internal/paginate and internal/export. The generator always emits against the CLI's current templates, so a project whose paginate package is six versions old would get a handler referencing a field its own copy of the struct does not declare, and the API would stop compiling with nothing in the error to point at the cause.

Your models, your services, your handlers and your frontend code are not in either set and are never rewritten.

What to do after

cd apps/api && go mod tidy # if the upgrade added a dependency
pnpm install # if it added a frontend one
grit doctor # the audit, which is where a new check shows up
grit test # the project's own suites

The upgrade tells you which of these it needs. grit doctor is worth running either way: a release often adds a check before it adds a fix, and the check is how you find out the fix applies to you.

How often

Grit releases often, and the version number is deliberately boring about it: a minor never breaks a running application. Upgrading is a thing to do when you want something from the changelog, not a thing to keep up with. A project three months behind upgrades in one command, because every repair checks its own preconditions and the ones that do not apply do nothing.