Update Project Templates¶
When this repo's template files change (new hooks, new egress rules, new
sections), consuming projects need to pick up those changes. Renovate handles
individual version pins in .pre-commit-config.yaml and .mise.toml, but
structural changes — new files, new sections, new hook entries — require the
update script.
Basic usage¶
# Interactive (prompts per differing file)
./scripts/update-project.sh /path/to/my-infra-project
# Report only — no writes
./scripts/update-project.sh /path/to/my-infra-project --dry-run
# Auto-apply all diffs (creates .bak for each replaced file)
./scripts/update-project.sh /path/to/my-infra-project --yes
--dry-run and --yes are mutually exclusive — passing both exits with an
error.
Status values¶
The status reported per file depends on the mode. NEW and OK apply in all
modes; the action statuses differ between --dry-run and the
interactive/--yes modes.
| Status | Mode | Meaning |
|---|---|---|
NEW |
all | File does not exist in the project; copied from upstream |
OK |
all | Byte-identical to upstream; nothing to do |
DIFF |
--dry-run |
Differs from upstream; would change (reported, not written) |
UPDATE |
interactive / --yes |
Overwritten with upstream (a timestamped .bak was saved) |
KEEP |
interactive / --yes |
The project's version was kept unchanged |
SKIP |
interactive / --yes |
The file was skipped (kept, but tracked separately in the summary) |
Interactive mode (differing files)¶
When a file differs, the script shows a short diff preview and prompts:
| Answer | Effect |
|---|---|
k (or Enter) |
Keep the project's version unchanged — Enter selects this default |
o |
Overwrite with upstream; saves a timestamped .bak alongside the file |
d |
Show the full diff via less -R if available, otherwise raw diff -u, then prompt again |
s |
Skip this file (kept, but counted separately in the summary) |
If stdin is not a TTY, the script cannot prompt and falls back to keeping the
project's version (the k action) for every differing file.
Overwrite safety¶
Existing files are never overwritten without an explicit o answer in
interactive mode or --yes. Every overwrite first copies the current file to
<path>.bak.<timestamp> alongside it, so the project's prior version is always
recoverable.
Marker-based sync for AGENTS.md and CLAUDE.md¶
AGENTS.md and CLAUDE.md use <!-- BASE:START --> / <!-- BASE:END -->
fences. For these two files the update script syncs only the section between
the markers — project content outside the markers is never touched.
If a project's copy has no markers (old format), the script falls back to the full-file interactive update and prints a migration hint.
Managed files¶
The script syncs ten files, grouped as required, recommended, editor config, and optional:
| File | Sync mode |
|---|---|
.devcontainer/devcontainer.json |
Full file |
.devcontainer/egress-allowlist.txt |
Full file |
.devcontainer/proxy.yaml |
Full file |
.devcontainer/env.sh |
Full file |
.gitignore |
Full file |
.pre-commit-config.yaml |
Full file |
AGENTS.md |
Base section only |
CLAUDE.md |
Base section only |
.editorconfig |
Full file |
.mise.toml |
Full file |
After updating devcontainer.json¶
If the run changes .devcontainer/devcontainer.json (outside --dry-run), the
script prints a reminder: in each open VS Code window for the project, run
Dev Containers: Rebuild Container to pick up the change.