Working Through a Template Update¶
This project is generated from
fastmcp-server-template
and tracks it. Once a week the copier-update workflow runs copier update
--trust and opens a pull request on the copier/update branch. Automated
runs advance one template major at a time, so a project several majors
behind sees one pull request per major, each with its own upgrade notes; a
manual dispatch with an explicit vcs_ref jumps straight to a chosen
release. This page is the procedure for that pull request,
whether you work through it yourself or hand it to a coding agent (the
applying-template-updates skill under .agents/skills/ is the same
procedure in agent-invocable form).
What the pull request carries¶
- The version delta (
vA.B.C→vX.Y.Z) and a compare link on the template repository. - The template's release notes for the target version, collapsed.
- The
UPGRADING.mdsections that apply to the jump, collapsed, with a link to the full file at the target ref. This is the template's record of the workcopier updatecannot do. - The list of files that carry conflict markers, if any.
- The resolution policy: the template side wins everywhere outside the regions this project owns.
The order of work¶
- Read the upgrade notes first. Every
UPGRADING.mdsection in the body names something a person must do: rename a variable, add a secret, rewrite a seeded test, add a.gitignoreline. Do those steps on thecopier/updatebranch before touching anything else; a note that is skipped now is a failure later, on a run nobody connects to this update. -
Resolve conflict markers.
copier updateruns a three-way merge and leaves diff3-style markers where a template change and a local change collide:<<<<<<< before updating(the local side),||||||| last update(the common base),=======, and>>>>>>> after updating(the template side). Resolving a hunk means keeping one side and deleting all four marker lines and the base block between|||||||and=======. Which side wins turns on whether the hunk is inside a sentinel block, and on what kind of block it is: -
Inside a sentinel block that invites your content, the local side is yours and stays. These are the
DOMAIN-*,CONFIG-*,PROJECT-*andDOCKERFILE-*families. Some of them wrap template-shipped content you extend rather than replace (PROJECT-EXTRAS,DOCKERFILE-UV-EXTRAS), so a template change inside one is possible: read both sides and keep your additions. - Inside a
GENERATED-*region the template side wins, and you do not resolve it by hand. Those regions are written byscripts/gen_config_surface.py, which re-runs at the end of the update and rewrites them from your own config. - Outside every sentinel block the template side is correct by policy: a local edit to a template-owned region is drift, and the fix is to move that content into a sentinel block or upstream it.
- Check the seeded-once files. Copier's
_skip_if_existslist names files that are written on the firstcopier copyand never touched again bycopier update. They are absent from the diff even when the template changed them. The update writes.copier-seeded-changes.mdat the repository root (the pull request body embeds it): a diff of every seeded path between the previous and target template versions, or an explicit statement that no seeded file changed. Work through that file and apply what applies by hand, keeping your local content. When the report says it could not be computed, fall back to the compare link and the "Before every upgrade" recipe in the template'sUPGRADING.md. The seeded paths, for reference:
.claude-plugin/**, src/markdown_vault_mcp/tools.py,
src/markdown_vault_mcp/resources.py, src/markdown_vault_mcp/prompts.py,
src/markdown_vault_mcp/domain.py, tests/conftest.py,
tests/test_smoke.py, tests/test_cli.py,
tests/public_import_surface.txt, CHANGELOG.md, docs/releases/**,
LICENSE, packaging/mcpb/manifest.json.in,
packaging/mcpb/pyproject.toml.in, packaging/mcpb/src/server.py,
packaging/mcpb/build.sh, .gitignore, .vale.ini,
.vale/styles/config/vocabularies/Base/accept.txt,
config-presentation.domain.yml, tests/test_config_wizard_domain.py,
src/markdown_vault_mcp/static/app.src.html.
Four more skip-listed paths are generated, not seeded: .env.example,
packaging/env.example, examples/*.env and
docs/javascripts/config-wizard/wizard-spec.json. The update
regenerates them from the config surface at its end, so never edit
them by hand; scripts/gen_config_surface.py --check in CI catches a
stale copy.
The list above is a snapshot; the authoritative one is
_skip_if_exists in the template's copier.yml at the target ref.
Treat a template change to a seeded file as a change to apply, never as
noise to ignore: the template ships these files as complete starting
points, and corrections to them reach this project only this way.
4. Refresh the lock file. uv lock after any floor change (the
upgrade notes say when), then uv sync --all-extras --all-groups
--locked.
5. Run the update gate. This is wider than the everyday gate, because
an update can leave drift that only these checks see:
git diff --check
git grep -nE '^(<<<<<<<|=======|>>>>>>>)'
uv lock --check
uv sync --all-extras --all-groups --locked
uv run python scripts/gen_config_surface.py --check
uv run ruff check .
uv run ruff format --check .
uv run mypy src/ tests/
uv run pytest -x -q
uv run mkdocs build --strict
uv run pre-commit run --all-files
An MCP Apps project also runs uv run python scripts/vendor_spa.py
--check. CI runs the same checks on the pull request.
6. Merge. The branch is recreated on the next weekly run, so leave
nothing uncommitted on it.
Working with a coding agent¶
Give the agent the pull request number and ask it to invoke the
applying-template-updates skill. The skill walks the six steps above and
stops where a decision is yours: a conflict inside a sentinel block, an
upgrade note it cannot perform (a secret to add, a repository setting),
and any seeded-file change it is not certain applies to this project. It
reports what it applied, what it skipped and why. Review that report
against the pull request body before merging.
When the update is not wanted¶
A template change can be wrong for this project. Do not resolve that by
editing a template-owned region; the next update reverts it. Either move
the divergence into a sentinel block the template preserves, or open an
issue on the template repository so the change gains a switch or a
sentinel. FORKING.md covers the last resort of detaching from the
template altogether.