@gallopsystems/agent-skills 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gallopsystems/agent-skills",
3
- "version": "1.14.0",
3
+ "version": "1.16.0",
4
4
  "description": "Gallop Systems agent skills, symlinked into .claude/skills (Claude Code) and .agents/skills (Codex) on install.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: copier-template
3
- description: Maintain a Copier project template and propagate updates to generated ("descendant") repos. Covers template anatomy (copier.yml, jinja, tasks), testing template changes, tagging/releasing versions, the automated update-notification PR pattern, and applying copier update in descendants with conflict resolution.
3
+ description: Maintain a Copier project template and propagate updates to generated ("descendant") repos. Covers template anatomy (copier.yml, jinja, tasks), testing template changes, tagging/releasing versions, the automated update-notification PR pattern, and applying copier update in descendants — bringing a repo fully to the latest template version while preserving its app behavior, with conflict resolution an autonomous agent can run end to end.
4
4
  ---
5
5
 
6
6
  # Copier Template Maintenance & Propagation
@@ -19,7 +19,7 @@ Patterns for the full lifecycle of a [Copier](https://copier.readthedocs.io/) pr
19
19
 
20
20
  - The **template repo** holds `copier.yml` (questions + settings + tasks) and a `template/` subdirectory of scaffold files (some `.jinja`-suffixed for substitution). **Git tags (`v*`) are the version protocol**; GitHub Releases are the changelog protocol.
21
21
  - Each **descendant** carries `.copier-answers.yml` recording its answers and `_commit: vX.Y.Z` — the template version it's on. Never hand-edit this file; `copier update` maintains it.
22
- - `copier update` re-renders from old-tag → newest tag and three-way merges against local changes. **It always jumps to the latest tag** (unless `--vcs-ref` pins one) — a notification PR advertising v1.5.0 may actually land v1.8.0 if the template moved on.
22
+ - `copier update` re-renders from old-tag → newest tag and three-way merges against local changes. **It always jumps to the latest tag** (unless `--vcs-ref` pins one) — a notification PR advertising v1.5.0 may actually land v1.8.0 if the template moved on. The job is **never to bump a version string** — it is to standardize whatever the template now sells while keeping this app's behavior intact. Hand-editing `_commit` or any version number to shrink a diff is always wrong; let `copier update` move it, and absorb the real changes.
23
23
  - Run copier via `uvx copier ...` (no global install needed). Templates with `_tasks` require `--trust` — without it copier refuses to render at all. Non-interactive contexts also need `--defaults` (and `--data key=value` for required questions without defaults).
24
24
 
25
25
  ## Direction of Change
@@ -79,7 +79,7 @@ echo '{"required_status_checks":{"strict":false,"contexts":["ci-success"]},"enfo
79
79
  ## Further Reading
80
80
 
81
81
  - **Template anatomy & testing changes**: [template-authoring.md](template-authoring.md)
82
- - **Applying an update in a descendant** (the conflict-resolution procedure): [applying-updates.md](applying-updates.md)
82
+ - **Applying an update in a descendant** (the full procedure — read-the-changes-first, multi-version deltas, `.rej` triage, silent-overwrite review, and autonomous merge-readiness): [applying-updates.md](applying-updates.md)
83
83
 
84
84
  ## Contributing Back
85
85
 
@@ -2,24 +2,68 @@
2
2
 
3
3
  Usually triggered by the automated "template update available" PR — its body contains the runbook; this file is the full procedure with the judgment calls spelled out.
4
4
 
5
- ## The sequence
5
+ **The point is not to bump the version number.** It is to standardize whatever the template now sells *while preserving this app's behavior*. For every release in range: understand what it changed, decide how it fits THIS app, and merge it in. A PR that only advances `_commit` / a version string without absorbing the template's actual changes is a failure, not a success — escalate instead of shipping one.
6
+
7
+ This procedure runs unattended end to end. There is no "ask the user" step mid-run — finish in one of the honest end states at the bottom.
8
+
9
+ ## Before you start: establish a green baseline
10
+
11
+ Post-update failures are only attributable if main was clean first.
6
12
 
7
13
  ```bash
8
- gh pr view <n> --json title,body # read the bot PR's instructions
9
- git checkout chore/template-update && git pull # the bot's static branch
14
+ gh run list --branch main --limit 1 --json conclusion,headSha # latest main CI green?
15
+ git checkout main && git pull --ff-only && git status --short # clean, up to date
16
+ ```
17
+
18
+ If main's CI is red *before* the update, note it — that failure is pre-existing and must not be attributed to (or silently fixed under cover of) the template bump. If you can't confirm a baseline, say so in the PR body.
10
19
 
20
+ **Diff the bot's branch against current main first.** The notification branch (`chore/template-update`) is cut far behind main — often tens of commits — and main has frequently *already* absorbed equivalent changes through normal feature work, so the real conflict set is much smaller than the version delta implies. Start the update from current main, not from the stale bot branch:
21
+
22
+ ```bash
23
+ gh pr view <n> --json title,body,headRefName
24
+ git log --oneline origin/main..origin/chore/template-update # how stale is the bot branch?
25
+ git checkout -B chore/template-update origin/main # rebuild the branch onto current main
26
+ ```
27
+
28
+ ## The sequence
29
+
30
+ ```bash
11
31
  # clean tree required — copier refuses otherwise
12
32
  git stash --include-untracked -m "wip before template update" # if dirty
13
33
 
14
- uvx copier update --trust --defaults
34
+ uvx copier update --trust --defaults --skip-tasks
15
35
 
16
36
  # triage
17
- git status --short # UU = unmerged (inline conflict markers)
18
- find . -name '*.rej' # hunks copier couldn't apply
19
- grep _commit .copier-answers.yml # confirm the new version
37
+ git status --short # UU = unmerged (inline conflict markers)
38
+ find . -name '*.rej' # hunks copier couldn't apply
39
+ grep _commit .copier-answers.yml # confirm the new (latest) version
40
+ ```
41
+
42
+ - **`--skip-tasks`**: `_tasks` (migrations, `npx volt-vue add`, seeds) only run on initial `copy`, but skip them explicitly so an update never fires surprise scaffold work (a stray migration, a regenerated component). Run any genuinely-needed task by hand afterward.
43
+ - **Dirty-tree refuses on untracked dirs/files too**, not just staged changes — `git stash` alone misses them. Use `--include-untracked`, or move local-tooling dirs (`.agents/`, `.claude/`, `.do/`, editor swap files) aside and restore them after.
44
+ - **The landed version is almost always higher than the bot PR advertised** — `copier update` targets the latest tag. Read the real version from `_commit` *after* the run and title the commit/PR from that. A multi-version jump means several releases land at once — budget for more conflicts.
45
+
46
+ ## Understand what changed before you resolve anything
47
+
48
+ Resolving conflicts blind produces a literal bump. Read the delta first.
49
+
50
+ **Enumerate every release in range**, not just the endpoints — copier jumped straight to the latest tag, so several releases may have landed at once:
51
+
52
+ ```bash
53
+ TPL=<template-url>
54
+ git ls-remote --tags --refs --sort=v:refname "$TPL" 'v*' # full tag list; pick OLD..NEW
55
+ gh release list --repo <template-owner/template-repo> --limit 20
56
+ gh release view v<X> --repo <template-owner/template-repo> # read each release's notes, oldest→newest
20
57
  ```
21
58
 
22
- Note the version it reports: `copier update` goes to the **latest** tag, which may be newer than the one the bot PR advertised. A multi-version jump means several releases' worth of changes land at once — budget for more conflicts.
59
+ Read the **cumulative compare** the bot links (or build it): `<template-url>/compare/v<OLD>...v<NEW>`. Scan specifically for:
60
+
61
+ - **Breaking changes** — renamed/removed questions, restructured `template/` layout, moved files (a factory file relocating, an auth file added).
62
+ - **CI / workflow** changes — new jobs, a changed gate (`ci-success`), runner/tool-version bumps.
63
+ - **Scaffold-owned files** the template overwrites silently (configs, lint/tsconfig, `main.css`, seed/factory/preview-login files).
64
+ - **New `_tasks` or dependencies** the descendant must now satisfy.
65
+
66
+ Write down, per release, what it sells. That list is the checklist the final PR body is graded against, and it tells you which conflicts are load-bearing vs cosmetic.
23
67
 
24
68
  ## Resolving conflicts
25
69
 
@@ -55,33 +99,129 @@ perl -0pi -e 's/^<<<<<<< before updating\n(.*?)^\|\|\|\|\|\|\| last update\n.*?^
55
99
  perl -0pi -e 's/^<<<<<<< before updating\n(.*?)^\|\|\|\|\|\|\| last update\n.*?^=======\n(.*?)^>>>>>>> after updating\n/$1$2/gms' <file>
56
100
  ```
57
101
 
58
- **`.rej` files**: copier couldn't apply a hunk (the local file diverged too far). Read the `.rej`, re-apply its *intent* manually — and check whether copier dropped project-specific content nearby (e.g. local vars in `.env.example`) — then `rm` the `.rej`.
102
+ After editing markers out, **`git add` each resolved file** — it stays `UU` until staged, and an unstaged `UU` later blocks `git stash pop` and the push.
59
103
 
60
- **Review the non-conflicted changes too.** Copier silently overwrites scaffold-owned files, and a new template assumption can be wrong for this project (e.g. a type coercion that assumes numeric IDs in a project using string IDs). `git diff` every copier-touched app-code file; revert what doesn't fit, and consider whether the template itself needs a fix.
104
+ **Scaffold files arrive written against the TEMPLATE's schema — adopt the feature, adapt it to yours; never a naive side-pick.** Files like preview-login, factories, seeds, and `auth.d.ts` ship assuming the template's columns (`first_name`/`last_name`, `deactivated_at`, numeric `id`). A descendant that diverged (a single `name` column, camelCase, string IDs) won't compile against them. Take the template's *feature* but rewrite it to the real schema: revert `Number(id)` coercions, fix the anchor-user/seed columns, drop selects on columns that don't exist, repair the matching test. After adopting any such file, grep it against the real `db.d.ts`:
61
105
 
62
- Final sweep before staging:
106
+ ```bash
107
+ grep -nE 'first_name|last_name|deactivated_at|Number\(' <adopted-file>
108
+ ```
109
+
110
+ **Convention migrations require porting, not side-picking.** When a release *moves* a convention (e.g. factories relocating from `server/test-utils/` into a shared `server/db/factories.ts` with a new `DbLike` type), a naive ours/theirs pick loses every project-specific factory. Port them into the new shape. Clone the template at the exact target tag to get the authoritative "after":
63
111
 
64
112
  ```bash
65
- grep -rn '<<<<<<<\|>>>>>>>' . --exclude-dir=node_modules
113
+ git clone --depth 1 --branch v<NEW> <template-url> /tmp/tpl-<NEW>
66
114
  ```
67
115
 
68
- ## Validate, commit, hand back
116
+ When a conflict reflects a deliberate template convention change (snake_case session fields, a renamed env var), migrating *toward* the template and updating the few consumers kills future churn — unless it's an intentional permanent fork (styled-PrimeVue vs Volt, a deliberately different env-var name), which you keep.
117
+
118
+ **`.rej` files** — copier couldn't apply a hunk because the local file diverged too far. A `.rej` is a unified diff of *just the rejected hunk*; the target file was left untouched there. Triage each:
119
+
120
+ ```bash
121
+ find . -name '*.rej'
122
+ cat path/to/file.ext.rej # ` ` context, `-` old template line, `+` new template line
123
+ ```
124
+
125
+ 1. **Read the hunk's intent** — the `+` lines are the new template content; `-` lines are what the old template had (which this project already diverged from).
126
+ 2. **Classify**: template intent (a feature/fix every descendant should get) vs a deliberate project customization at that spot. Template intent → apply it by hand into the live file, adapting to local naming. Project customization → keep the project's version; note the intentional skip.
127
+ 3. **Check adjacent content** — copier may have dropped project-specific lines near the hunk (local vars in `.env.example`, an extra `package.json` script). Diff the region against `origin/main` before trusting the live file.
128
+ 4. **`rm` the `.rej`** only after the live file reflects your decision — a committed `.rej` is a defect.
129
+
130
+ `.env.example` recurs as a separate `.rej` even when everything else merged inline — always check for both.
131
+
132
+ **Review every silently-overwritten file — a clean, conflict-free merge can still be harmful.** Copier overwrites scaffold-owned files with **no markers**, and its text merge is structure-blind: it has duplicated `public:` inside `runtimeConfig` and the entire `@theme`/CSS-token block in `main.css`, both of which would silently break the app. `git diff` everything the update touched, not just the `UU` files:
133
+
134
+ ```bash
135
+ git diff origin/main --stat # everything the update touched
136
+ git diff origin/main -- <file> # per-file: keep / revert / merge — watch for duplicated keys/blocks
137
+ ```
138
+
139
+ - A new template assumption can be wrong for this project → revert the bad part, note it, and consider whether the *template* needs the fix (open a template issue/PR if other descendants are affected).
140
+ - An overwritten config the project had customized → re-apply the project's customization on top of the template's new baseline.
141
+
142
+ **CI workflows get explicit, line-by-line attention — never blind-accept them:**
143
+
144
+ 1. Diff the new workflow: `git diff origin/main -- .github/workflows/`.
145
+ 2. Understand **what the new template CI does** — new jobs, changed triggers, the gate job (`ci-success`), runner/tool versions.
146
+ 3. Decide, per change, **whether it's an improvement this app wants**, and keep it.
147
+ 4. **Preserve the app's own CI** — project-specific jobs, secrets, deploy steps, matrix tweaks the template doesn't know about. Merge them on top; don't let the overwrite drop them.
148
+ 5. **Validate the adopted commands actually fit**: does `test:run` accept `--shard`? do the new `ci-success` `needs:` reference the repo's real job names? does a new job hard-code an env name the harness doesn't read (e.g. `TEST_POSTGRESQL_CONNECTION_STRING` when the harness reads `NUXT_DATABASE_URL_TEST`)? does the Postgres service version match? Conflict-resolved YAML can be valid yet reference scripts/jobs that don't exist.
149
+ 6. If the gate job name or required contexts changed, reconcile with branch protection (see SKILL.md → *Branch Protection in Descendants*).
150
+
151
+ A chore that recurs every single update (e.g. `fmt:check` always failing on arrival) is a signal to fix the **template**, not the descendant — flag it upstream.
152
+
153
+ Final sweep before staging — both marker kinds and leftover `.rej`, excluding vendored noise:
154
+
155
+ ```bash
156
+ grep -rnE '^<<<<<<< |^>>>>>>> ' . --exclude-dir=node_modules --exclude-dir=.yarn # .yarn release contains literal >>>>>>>
157
+ find . -name '*.rej' # must be empty
158
+ ```
159
+
160
+ ## Validate, commit, and decide merge-readiness
69
161
 
70
162
  ```bash
71
163
  git add -A # includes .copier-answers.yml — it must be committed with the update
72
164
  yarn install && yarn typecheck && yarn lint && yarn fmt:check && yarn test:run
165
+ git status --short # re-check for newly-generated install artifacts (a new symlink dir, lockfile churn)
73
166
  ```
74
167
 
75
- Commit as `chore: update to template vX.Y.Z` with a body listing the notable upstream changes **and each conflict resolution with its rationale** — that's the audit trail for the squash-merge. Then retitle the bot PR (`gh pr edit <n> --title "chore: update to template vX.Y.Z"`), push, watch CI, and ask the user before merging. The bot's empty placeholder commit is fine — it disappears in the squash.
168
+ - **Brand-new scaffold files can fail `fmt:check` on arrival** (a new `.mcp.json` with a leading blank line) — even a conflict-free update needs the full suite, because new files aren't pre-formatted to your formatter.
169
+ - **A template/Nuxt bump drags dependency-alignment failures that look like update breakage** — e.g. a `vue-router@^4` pin throwing `ERR_PACKAGE_PATH_NOT_EXPORTED` after the bump wanted `^5`, or a newly-strict `@vue/language-core` flagging valid Vue. Fix the dependency/toolchain drift; don't revert the template change.
170
+ - **A bumped post-install dep can generate new artifacts the old `.gitignore` misses** (a `.agents/` symlink dir). Add the ignore + `git rm -r --cached <dir>`, but still stage `.copier-answers.yml`.
171
+ - **Recover non-destructively.** `git reset --hard` / `git stash drop` risk discarding the update work (and are blocked under agent auto-mode). Prefer `git checkout --ours/--theirs`, `git rm --cached`, `git merge --abort`. If a `reset --hard origin/<branch>` is genuinely warranted, first prove the commits being discarded are already in main.
172
+
173
+ **If a check fails, prove whether it's pre-existing** before blaming the update: `git worktree add /tmp/<proj>-main origin/main`, symlink `node_modules`, rerun the failing check there. A byte-identical failure on main means fix-forward in this PR, not a regression. A local lefthook pre-push hook may block on such a pre-existing failure — only bypass (`--no-verify`) once you've proven it reproduces on pristine main and CI is the real gate; push with `--force-with-lease` since the branch was rebuilt.
174
+
175
+ ### Commit / PR body template
176
+
177
+ Commit as `chore: update to template vX.Y.Z`. The body is the audit trail for the squash-merge — it must show the update was *absorbed*, not just stamped:
178
+
179
+ ```
180
+ chore: update to template vX.Y.Z
181
+
182
+ Version: vOLD → vNEW (copier jumped to latest)
183
+ Releases included: vA, vB, vNEW
184
+
185
+ Notable upstream changes (what the template now sells):
186
+ - vA: <feature/fix> — applied / adapted as <how>
187
+ - vB: <CI change> — kept <X>, preserved app's <Y>
188
+ - vNEW: <breaking change> — handled by <how>
189
+
190
+ Conflicts & resolutions:
191
+ - path/to/file: kept ours (hand-customized) — <why>
192
+ - path/to/file: took theirs (untouched scaffold)
193
+ - path/to/file: merged — project <X> + template <Y>
194
+ - path/to/file.rej: applied template intent by hand / intentionally skipped — <why>
195
+
196
+ Reverted template changes (wrong for this app):
197
+ - <file>: <what + why>; template issue: <link or "n/a">
198
+
199
+ Validation: typecheck / lint / fmt / tests — <pass | pre-existing failure on main: link>
200
+ Baseline: main CI was <green | red (link)> before this update.
201
+ ```
202
+
203
+ Retitle the bot PR to match: `gh pr edit <n> --title "chore: update to template vX.Y.Z"`, push, watch CI. The bot's empty placeholder commit disappears in the squash.
204
+
205
+ ### What "done" means
206
+
207
+ Land in one of three honest end states:
208
+
209
+ - **`pr_open`, ready for human review** — every release in range absorbed, all conflicts resolved with rationale, `.rej`/markers gone, CI green (or failure proven pre-existing), PR body complete. **Do not self-merge a template update** — stop here for a human to merge. This is the normal success state.
210
+ - **`pr_open`, escalated** — you hit a conflict you cannot resolve safely (a breaking change whose correct adaptation is ambiguous, a template assumption that contradicts core app behavior, CI you can't get green without guessing). **Escalating is correct.** Push what you have, mark the PR a **draft**, and write the blocker explicitly in the body: which release, which file, the two options, why you stopped. **Never paper over it by reverting the hard part and shipping a literal version bump** — a bump that drops the template's real change is worse than an open question.
211
+ - **No change needed** — `_commit` already equals the latest tag (main absorbed it). Close the bot PR with a note.
76
212
 
77
- **If something fails after the update**, prove whether it's pre-existing before blaming the update: `git worktree add /tmp/<proj>-main origin/main`, reuse node_modules (symlink), rerun the failing check there. A byte-identical failure on main means fix-forward in this PR, not a regression.
213
+ The bar: would a reviewer reading the PR body see *what each version changed and how it was fit into this app*? If not, it is not done.
78
214
 
79
215
  ## Troubleshooting
80
216
 
81
217
  | Symptom | Fix |
82
218
  |---|---|
83
- | `Destination repository is dirty; cannot continue` | `git stash --include-untracked` — plain `git stash` misses untracked files (including editor swap files), which still count as dirty |
219
+ | `Destination repository is dirty; cannot continue` | `git stash --include-untracked` — plain `git stash` misses untracked files/dirs (editor swap files, local-tooling dirs), which still count as dirty |
84
220
  | Copier refuses to render at all | Template has `_tasks` — add `--trust` |
85
221
  | Hangs or fails in non-interactive shells | Add `--defaults` (and `--data key=value` for questions without defaults) |
222
+ | Update wants to run scaffold tasks (migrations, component installs) | Add `--skip-tasks`; run any genuinely-needed task by hand |
86
223
  | Update landed a version you didn't expect | `copier update` always targets the latest tag; pin with `--vcs-ref v<X.Y.Z>` if you need a specific one |
224
+ | Conflict marker grep returns hits in `.yarn/` | False positives from the vendored yarn release — `--exclude-dir=.yarn` |
225
+ | An auto-merged file looks fine but the app breaks | Structure-blind text merge duplicated a key/block (`runtimeConfig.public`, `main.css` `@theme`) — `git diff origin/main` the non-conflicted files too |
226
+ | Tempted to just edit `_commit` / a version string to make the diff small | Stop — that's the literal-bump failure. The template's changes must be merged, not stamped. Re-run `copier update` clean; if conflicts are unresolvable, escalate (see *What "done" means*) |
87
227
  | Template change is wrong for this project | Revert locally, note it in the commit body, open a template issue/PR if other descendants are affected |