feat(project-bootstrap): v1.3.0 — idempotent CLAUDE.md merge on upgrade
Step 5 was binary on upgrade (append whole template / leave alone), so projects bootstrapped before v1.2.0 silently missed new canonical triggers (`check across all projects`, `we're on Windows`) on re-run. Now upgrade reads existing CLAUDE.md, substring-diffs vs template, preserves a deliberately-pinned platform line, and appends only missing lines after explicit confirm. Re-runs are no-ops. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
49
.wiki/concepts/bootstrap-claude-md-merge.md
Normal file
49
.wiki/concepts/bootstrap-claude-md-merge.md
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "project-bootstrap@1.3.0 — idempotent CLAUDE.md merge on upgrade"
|
||||
type: concept
|
||||
updated: 2026-04-30
|
||||
---
|
||||
|
||||
# project-bootstrap@1.3.0 — idempotent CLAUDE.md merge on upgrade
|
||||
|
||||
_2026-04-30._
|
||||
|
||||
## Problem
|
||||
|
||||
Step 5 of `project-bootstrap` (≤1.2.0) treated `CLAUDE.md` as binary:
|
||||
|
||||
- **File missing** → write template.
|
||||
- **File exists** → ask "append the whole template, or leave as is?"
|
||||
|
||||
Both branches fail the upgrade case. Append-the-whole-template duplicates trigger lines; leave-as-is leaves the file behind whenever the canonical template gains new lines. Concretely: the v1.2.0 release added `check across all projects` (→ `using-projects-meta`) to the template — but every project bootstrapped before v1.2.0 silently kept its old CLAUDE.md and never got the new trigger when re-run on the upgrade path. Same gap for `we're on Windows` (→ `active-platform`).
|
||||
|
||||
## Decision
|
||||
|
||||
Step 5 in v1.3.0 splits along the existing fork:
|
||||
|
||||
- **Init (file missing)** — unchanged. Write the template, substitute the platform line on non-Windows hosts.
|
||||
- **Upgrade (file exists)** — read existing → diff against template → confirm → append-only-missing.
|
||||
|
||||
Diff rules:
|
||||
|
||||
- Trigger lines (everything except the platform line): present iff any existing line, after `trim` + `tolower`, contains the template line's text. Substring match, not equality — tolerates user rewording or trailing punctuation. Avoids false-positive duplicates while preserving canonical wording for missing ones.
|
||||
- Platform line: present iff any existing line matches `we're on (windows|linux|macos)` case-insensitively. If the user pinned a different platform on purpose, leave it. Only append the host-appropriate platform line when none of the three is present.
|
||||
|
||||
After diff: if zero missing lines → no-op. Otherwise show the diff to the user, wait for explicit confirm, then append (don't rewrite — file order preserved). Re-runs become no-ops once canon is reached.
|
||||
|
||||
## Why merge, not overwrite
|
||||
|
||||
User-edited CLAUDE.md often carries project-specific lines beyond the template (custom triggers, comments, ordering preferences). Overwrite would clobber them; equality-match would miss substring rephrasings. Substring + append-only is the minimum-violence reconcile that keeps canon current without trampling user intent. The confirmation gate stays — append is still a write.
|
||||
|
||||
## Composition with `[bootstrap-recommend-projects-meta]`
|
||||
|
||||
`[bootstrap-recommend-projects-meta]` (⚪ Ready, Step 5.7 future work) covers the **machine-level** dependency: detect missing `projects-meta-mcp` MCP server and recommend `setup-projects-meta`. This task covers the **project-level** trigger merge. They compose cleanly:
|
||||
|
||||
- 5.7 makes the trigger functional on the host.
|
||||
- 1.3.0 ensures the trigger is actually present in the project's CLAUDE.md.
|
||||
|
||||
Either alone is partial; together they close the loop for the `check across all projects` line specifically and for any future canonical trigger generally.
|
||||
|
||||
## Pattern: idempotent reconcile of canonical config
|
||||
|
||||
Same pattern other setup-skills can borrow when they own a canonical file shape on disk: read existing → diff against canon → confirm → append-only-missing. Avoids the binary "create from template / leave alone" trap that's good for greenfield and bad for upgrade.
|
||||
@@ -13,6 +13,7 @@ Catalog of all wiki pages. One line per page, organized by type. Updated on ever
|
||||
## Concepts
|
||||
|
||||
- [active-platform-decision.md](concepts/active-platform-decision.md) — why `active-platform` is a skill (not a memory entry); why default = Windows; how it's wired into `project-bootstrap`
|
||||
- [bootstrap-claude-md-merge.md](concepts/bootstrap-claude-md-merge.md) — project-bootstrap@1.3.0 — Step 5 upgrade path becomes idempotent merge (read → diff vs template → confirm → append missing); fixes silent gap where pre-1.2.0 projects never picked up new canonical triggers (`check across all projects`, `we're on Windows`)
|
||||
- [bootstrap-manifest.md](concepts/bootstrap-manifest.md) — record of which `project-bootstrap` / `setup-wiki` / `setup-tasks` versions initialized this project's `.wiki/` and `.tasks/` layout (overwritten on re-bootstrap; history in git)
|
||||
- [build-notes.md](concepts/build-notes.md) — why `build.ps1` exists alongside `build.sh`; PS 5.1 backslash-in-zip gotcha; how to extract a `.skill`
|
||||
- [install-portability.md](concepts/install-portability.md) — `install.sh` / `build.sh` rewritten to drop `mapfile` (bash 4+) and `find -printf` (GNU only) so stock macOS (bash 3.2 + BSD find) works
|
||||
|
||||
@@ -36,3 +36,4 @@ Parseable: `grep "^## \[" .wiki/log.md | tail -20`.
|
||||
## [2026-04-30] refactor | project-bootstrap re-run on this repo (upgrade mode) — setup-wiki noop, setup-tasks noop, CLAUDE.md unchanged (matches template), bootstrap-manifest.md written: project-bootstrap@1.1.0 / setup-wiki@1.0.0 / setup-tasks@1.0.0
|
||||
## [2026-04-30] decision | project-bootstrap@1.2.0 — CLAUDE.md template gains `check across all projects` (verbatim trigger from using-projects-meta description); installs auto-load cross-project tasks + shared-wiki access in every bootstrapped repo; no Step 5.7 dependency-check mirror — Prerequisites pointer in using-projects-meta is self-correcting; local CLAUDE.md, both READMEs, dist/.skill, projects-meta-skills concept page synced
|
||||
## [2026-04-30] decision | Step 5.7 mirror of Step 5.6 (projects-meta-mcp dependency detector / `setup-projects-meta` recommendation) accepted as future work; tracked as ⚪ Ready task `[bootstrap-recommend-projects-meta]`; deferred until first observed fresh-machine miss so detector signal is informed by real failure mode; concept page `projects-meta-skills.md` updated to reflect new stance
|
||||
## [2026-04-30] decision | project-bootstrap@1.3.0 — Step 5 upgrade path turned idempotent: read existing CLAUDE.md → substring-diff vs template → confirm → append-only-missing; closes silent gap where pre-1.2.0 projects never picked up new canonical triggers (`check across all projects`, `we're on Windows`); platform line preserved if user pinned a non-host one; concept page `bootstrap-claude-md-merge.md` written; README CLAUDE.md row updated to note idempotent merge
|
||||
|
||||
Reference in New Issue
Block a user