Skip to content

Reconcile inconsistent .claude/ tracking across ~/Developer repos #62

Description

@twistedmelonman

Problem

27 repos under ~/Developer have a .claude/ directory. There is no consistent policy on whether it is committed:

  • 14 TRACKED
  • 12 IGNORED (11 via .gitignore, 1 via .git/info/exclude)
  • 1 NEITHER (claude-config — untracked and un-ignored)

The split is accidental, not deliberate. The standard scaffold (README.md, config.sh.template, hooks/extensions/example.sh.disabled) hashes to 6a8d79ff37dfa1b47aa20ddfb415ba7e in every repo sampled from both camps — identical bytes, tracked in some and ignored in others depending only on whether someone ran git add after the scaffolder fired.

Filing here because dev-env owns the template content all these directories are copies of.

Current state

Repo State Beyond scaffold
archive-resolver IGNORED
claude-config NEITHER settings.local.json
claude-wrapper TRACKED settings.local.json, scheduled_tasks.lock
dev-env TRACKED settings.local.json
dotfiles IGNORED plans/
dumbify TRACKED
financial-agent TRACKED pre-launch.sh, secrets.op.template, secrets.op*, settings.local.json, scheduled_tasks.lock, plans/
github-workflows IGNORED settings.local.json, plans/
Gmail-MCP-Server TRACKED skills/pr-review-sop/SKILL.md
homebrew-tap IGNORED (local)
kebab-tax TRACKED settings.local.json, secrets.op
LaunchAgents IGNORED
lock-sync TRACKED
mac-dev-server-setup IGNORED
mac-server-setup IGNORED 4 scratch .md files, settings.local.json
networth-agent TRACKED pre-launch.sh, secrets.op.template
personify TRACKED settings.local.json
pr-review TRACKED
qwen-sidebar TRACKED settings.local.json
reliquarist IGNORED
scripts IGNORED settings.local.json
slack-mcp TRACKED
smartwatermelon-marketplace TRACKED
spokane-snow TRACKED
tensegrity TRACKED settings.local.json
vpn-lan-bridge IGNORED
x-thread-reader-unpacked IGNORED

* on disk, correctly untracked

Cataloguing caveat: check .git/info/exclude too

A repo can be excluded in two places, and only one of them is visible to
anyone else:

  • .gitignore — committed, shared, greppable from a clone
  • .git/info/exclude — local to a single clone, never committed

When re-surveying, check both. git check-ignore -q .claude honours both
sources, so a catalogue built on it alone reports "IGNORED" without saying
which mechanism — and the two need different follow-up. A .gitignore entry
is done; an info/exclude entry still needs one if the intent is for the
policy to apply to every clone and every collaborator.

To distinguish them:

git check-ignore -v .claude/   # prints the source file and line number

homebrew-tap is now exactly this case: .claude/ was added to
.git/info/exclude locally rather than committed to .gitignore, which is a
deliberate hold pending smartwatermelon/dotfiles#220. It reads as handled in
this working copy but carries no shared signal, and a fresh clone would
scaffold an untracked .claude/ again. The table below reflects that as
"IGNORED (local)".

Also worth noting for the TRACKED column: git ls-files .claude returning
rows does not mean the whole directory is tracked — several repos track a
subset while the rest sits untracked. Catalogue per-file, not per-directory.

Proposed policy

Contents fall into three categories, and only the third is worth committing:

  1. Generated scaffoldREADME.md, config.sh.template, example.sh.disabled. Reproducible on demand by the scaffolder. Committing it means N identical copies that go stale independently when the template changes. → ignore
  2. Machine-local statesettings.local.json, plans/, scheduled_tasks.lock, scratch notes. The .local. infix is Claude Code's own "not shared" convention. → ignore
  3. Real project configpre-launch.sh, secrets.op.template, skills/. Things a fresh clone or a collaborator actually needs. → commit

So: ignore .claude/ by default, negate the exceptions.

.claude/
!.claude/pre-launch.sh
!.claude/secrets.op.template
!.claude/skills/

Only financial-agent, networth-agent, and Gmail-MCP-Server currently hold category-3 content.

Work

  • Confirm the policy above (or pick the opposite default and apply it uniformly)
  • 11 IGNORED repos: no change beyond verifying the negation lines where needed
  • 1 NEITHER repo (claude-config): add the gitignore stanza
  • 14 TRACKED repos: git rm -r --cached .claude/ for category-1/2 content, add the stanza, keep category-3 committed
  • kebab-tax: commits .claude/secrets.op rather than secrets.op.template. Contents are op:// references, not secret values, so nothing is currently leaked — but it is the only repo committing the resolved filename, and if that file is ever populated in place it becomes a live-secrets file in git history. Rename to .template.
  • mac-server-setup: 4 scratch .md files (PHASE2_COMPLETION_CONTEXT.md, doc-audit-progress.md, …) — session detritus, delete rather than reclassify
  • claude-config: .claude/worktrees/ holds agent worktrees; make sure the stanza covers it

Related

smartwatermelon/dotfiles#220 fixes the source: git/template/hooks/post-checkout scaffolds .claude/ into every new clone without writing a gitignore entry, which is what produced this drift. That one stops the bleeding for new repos; this issue cleans up the existing 27. Worth doing #220 first so the two agree on the policy.

Surfaced while closing smartwatermelon/homebrew-tap#19.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions