Skip to content

Stop clobbering the Claude settings.local.json personal layer#729

Merged
alexander-yevsyukov merged 7 commits into
masterfrom
claude-settings-local-personal-layer
Jul 8, 2026
Merged

Stop clobbering the Claude settings.local.json personal layer#729
alexander-yevsyukov merged 7 commits into
masterfrom
claude-settings-local-personal-layer

Conversation

@alexander-yevsyukov

@alexander-yevsyukov alexander-yevsyukov commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Config hygiene for Claude Code settings, plus a hardening fix to the .gitignore
merge. (An earlier revision of this PR also excluded .idea/misc.xml; that is now
handled on master by #728, so this PR defers to it — see "Reconciliation" below.)

1. Claude settings.local.json — the personal-override layer (primary)

In Claude Code, .claude/settings.local.json is the gitignored, per-developer
personal-override layer (user < project < local). migrate distributed and overwrote
it on every pull (the Hugo-only branch even rm -f'd it), silently wiping personal
overrides and forcing the file into Git.

  • migrate no longer creates, overwrites, or deletes it.
  • Its genuinely org-wide permissions (Skill(pre-pr), Skill(pre-pr:*),
    version-bumped) move into the shared settings.json / settings-hugo.json; the
    echo "exit=$?" cruft is dropped.
  • The distributed .gitignore baseline ignores /.claude/settings.local.json; config
    un-tracks its own copy.

2. plansDirectory → gitignored .claude/plans

Both distributed templates set "plansDirectory": ".claude/plans", and the baseline
ignores /.claude/plans/. Claude Code plan-mode files get harness-assigned random slugs,
so they belong in a gitignored scratch dir; durable, meaningfully-named task docs stay
under .agents/tasks/. (Mirrors agents PR #30.)

3. Harden the .gitignore merge against retired baseline negations

scripts/update-gitignore.sh now strips "retired" baseline !-negations from a
consumer's repo-local region in both the first-migration and steady-state paths, so a
negation config has removed from the baseline can't survive in repo-local (after the
managed block) and re-include a now-ignored path. First entry: !.idea/misc.xml (the
negation #728 retired). Complements #728's migrate-side scrub by fixing it at-source,
with two new regression cases in scripts/test-update-gitignore.sh.

4. Bundled: ToolBase2.0.0-SNAPSHOT.403

A small, pre-existing lockstep version bump in buildSrc/.../ToolBase.kt. Publishes on
merge.

Reconciliation with #728

master merged #728 ("Stop tracking .idea/misc.xml; treat it as project-local"), which
handles the .idea/misc.xml exclusion more completely (config keeps its own copy as the
shared seed; consumers untrack via migrate). This PR's earlier misc.xml changes were
dropped in favor of #728 — the branch now contains no misc.xml changes of its own, and
config's .idea/misc.xml stays tracked. The only related piece kept is the
update-gitignore.sh retired-negation hardening (#3), which is broader than misc.xml and
carries test coverage.

Migration note for consumers

A repo that already committed .claude/settings.local.json keeps tracking it until a
one-time git rm --cached .claude/settings.local.json (gitignore does not untrack an
already-tracked file).

Verification

  • bash -n migrate; scratch simulation confirms a developer's personal
    settings.local.json survives a pull; the moved permissions + plansDirectory land in
    the distributed templates.
  • scripts/test-update-gitignore.sh — full suite passes, including the new
    retired-negation cases (first-migration + steady-state); Secrets invariants intact.
  • Reviewers (pre-Stop tracking .idea/misc.xml; treat it as project-local #728-merge): spine-code-review, review-docs, dependency-audit,
    kotlin-engineer — all APPROVE.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adjusts how the config repo distributes Claude Code settings so ./config/pull no longer overwrites developers’ personal .claude/settings.local.json, while moving the shared permissions into the committed shared settings templates.

Changes:

  • Stop distributing (and deleting) .claude/settings.local.json; move shared permissions into .claude/settings.json / .claude/settings-hugo.json.
  • Update .gitignore to ignore .claude/settings.local.json (and add an ignore for .claude/plans/), and remove .idea/misc.xml from being tracked/shared.
  • Bump ToolBase snapshot version from 2.0.0-SNAPSHOT.402 to 2.0.0-SNAPSHOT.403.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
README.md Updates documentation about Claude settings distribution behavior.
migrate Stops touching settings.local.json and adds logic around .idea/misc.xml handling.
buildSrc/src/main/kotlin/io/spine/dependency/local/ToolBase.kt Bumps ToolBase snapshot version.
.idea/misc.xml Removes tracked IntelliJ misc.xml from the repo.
.gitignore Stops re-including .idea/misc.xml; ignores Claude plan scratch + personal local settings file.
.claude/settings.local.json Removes the config-distributed local settings layer.
.claude/settings.json Adds plansDirectory and moves shared allowlist entries here.
.claude/settings-hugo.json Adds plansDirectory and shared allowlist entries for Hugo-only repos.
.agents/tasks/claude-settings-local-personal-layer.md Adds a task-plan document for this change.
Files not reviewed (1)
  • .idea/misc.xml: Generated file

Comment thread migrate
Comment thread .claude/settings.json
Comment thread .agents/tasks/claude-settings-local-personal-layer.md Outdated
@alexander-yevsyukov alexander-yevsyukov force-pushed the claude-settings-local-personal-layer branch from e9c9aef to d71ee0e Compare July 7, 2026 21:01
@alexander-yevsyukov alexander-yevsyukov changed the title Stop distributing the Claude settings.local.json personal layer Stop tracking/distributing per-developer config files (Claude & IDEA) Jul 7, 2026
@alexander-yevsyukov alexander-yevsyukov moved this from 🏗 In progress to In Review in v2.0 Jul 7, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4158d5e68e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .gitignore Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f274b46e7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread migrate Outdated
alexander-yevsyukov and others added 7 commits July 8, 2026 14:03
`migrate` copied `.claude/settings.local.json` into every consumer and
overwrote it on each `./config/pull` (the Hugo-only branch even `rm -f`'d
it). In Claude Code that file is the gitignored, per-developer
personal-override layer (precedence user < project < local), so
distributing it silently wiped a developer's overrides and forced the file
into Git — contrary to its "local, not committed" role.

- `migrate` no longer creates, overwrites, or deletes `settings.local.json`;
  a `./config/pull` leaves the personal file untouched.
- The genuinely org-wide permissions it carried (`Skill(pre-pr)` and the
  `version-bumped` guard) move into the shared `settings.json` /
  `settings-hugo.json`; the `echo "exit=$?"` session cruft is dropped.
- The distributed `.gitignore` baseline now ignores
  `/.claude/settings.local.json`, and config un-tracks its own copy to
  dogfood the personal-layer contract.
- Both distributed templates gain `"plansDirectory": ".agents/tasks"` so
  plan/status docs default into the repo-local, non-clobbered task dir
  org-wide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap two over-length lines and correct the stale "not part of the PR" line (the plan file is committed as the tracked task doc, per AGENTS.md).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
"doing either" implied two actions but three precede it; say "any of these ... or forced the file into Git" (per docs review). Comment-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude Code's plan-mode files get harness-assigned random slugs, so routing them into `.agents/tasks/` would mix random-named files into the meaningfully-named task namespace. Point `plansDirectory` at a gitignored `.claude/plans/` scratch dir instead (in both distributed templates), and ignore it in the baseline; durable, agent-authored task docs stay under `.agents/tasks/`. Mirrors agents PR #30.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The work is complete and the PR description is the durable record. Per .agents/tasks/README.md the plan file is deleted rather than landing in master; this also resolves the missing-frontmatter review note by not shipping the file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A consumer whose `.gitignore` is a legacy unmarked raw copy of an older baseline
still carries `!.idea/misc.xml` (the re-inclusion the current baseline dropped).
`update-gitignore.sh`'s first-migration path preserves every consumer negation
into the repo-local block, which sits AFTER the managed baseline — so, gitignore
being last-match-wins, the stale negation re-included `.idea/misc.xml`, leaving it
committable even after a `git rm --cached`. An already-migrated consumer hits the
same via the steady-state path (the negation was baked into repo-local by an
earlier first-migration). The secret trailer does not catch this — `misc.xml` is
not a secret glob.

Add a `retired_negations` set (currently `!.idea/misc.xml`) and strip it from the
repo-local region in BOTH the steady-state and first-migration paths, so the
baseline's `.idea/*.xml` ignore wins. Genuine consumer negations and custom lines
are untouched.

Covered by two new regression cases in `test-update-gitignore.sh` (steady-state
and first-migration); the full suite passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alexander-yevsyukov alexander-yevsyukov force-pushed the claude-settings-local-personal-layer branch from 388946b to fcbe1a3 Compare July 8, 2026 13:06
@alexander-yevsyukov alexander-yevsyukov merged commit 020ce20 into master Jul 8, 2026
3 checks passed
@alexander-yevsyukov alexander-yevsyukov deleted the claude-settings-local-personal-layer branch July 8, 2026 13:07
@alexander-yevsyukov alexander-yevsyukov changed the title Stop tracking/distributing per-developer config files (Claude & IDEA) Stop clobbering the Claude settings.local.json personal layer Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants