project-updater
Update project .claude/ configuration from ~/.claude/template/. Detects technologies to copy only relevant rules. Use when updating a project from template or after template changes.
SKILL.md
| Name | project-updater |
| Description | Update project .claude/ configuration from ~/.claude/template/. Detects technologies to copy only relevant rules. Use when updating a project from template or after template changes. |
name: project-updater description: > Update project .claude/ configuration from ~/.claude/template/. Detects technologies to copy only relevant rules. Use when updating a project from template or after template changes. allowed-tools: [Bash, AskUserQuestion]
Project Updater
Update project .claude/ from ~/.claude/template/ using the deterministic update script.
Usage
~/.claude/skills/project-updater/update-project.sh
The script is report-only - it shows what differs between template and project but makes no changes. Claude reads the report and decides which files to copy using Read/Write tools.
Technology Detection
The script uses ~/.claude/scripts/detect-technologies.sh to determine which tech rules to sync:
| Detection Method | Examples |
|---|---|
| package.json dependencies | next, @supabase/supabase-js, tailwindcss |
| Config files | next.config.js, vitest.config.ts, playwright.config.ts |
| Directories | supabase/, components/ui/ |
Only rules for detected technologies are synced. When a technology is removed from a project, its rules become "unused".
Tool Detection
The script also detects workflow tools by directory existence:
| Directory | Detected Tool | Files Synced |
|---|---|---|
openspec/ | OpenSpec | workflow/openspec.md, workflow/workflow-integration.md, spec-review/, wrap.md, hooks |
Files for disabled tools are skipped, not copied.
Hook Syncing
The script also syncs Claude Code hooks from template based on tool detection. Hooks are defined in ~/.claude/config/sync-config.yaml under each tool's hooks section.
Example hook definition in sync-config.yaml:
tools:
openspec:
detect:
directories:
- openspec/
hooks:
PostToolUse:
- matcher: "ExitPlanMode"
type: "prompt"
prompt: "/execute-plan"
_templateId: "openspec:execute-plan"
How it works:
- Template hooks have a
_templateIdfield to distinguish them from project hooks - Project hooks without
_templateIdare preserved - Same
_templateId= project override wins (template version skipped) - Hooks are added to
.claude/settings.json
Disable a template hook:
Add the template ID to _disabledTemplateHooks in project settings.json:
{
"_disabledTemplateHooks": ["openspec:execute-plan"],
"hooks": { ... }
}
Apply hooks:
~/.claude/skills/project-updater/sync-hooks.sh --apply
Folder Structure
Template rules are organized in folders:
~/.claude/template/rules/
├── workflow/ # OpenSpec, task workflow, session management
├── tech/ # Technology-specific (Next.js, Supabase, etc.)
├── patterns/ # Cross-cutting patterns (data retention, organization)
└── meta/ # Process rules (research, documentation lookup)
The sync script handles nested folders automatically. Project-specific rules should go in .claude/rules/project/ which is NOT synced from template.
Path Mapping
The template uses hierarchical organization while projects use flat directories for skills:
| Template | Project |
|---|---|
skills/quality/review/ | skills/review/ |
skills/quality/pr-check/ | skills/pr-check/ |
skills/workflow/gitbutler/ | skills/gitbutler/ |
The script handles this mapping internally - reported paths are template-relative.
Opting Out of Template Files (.syncignore)
Create .claude/.syncignore to permanently opt out of specific template files:
# Don't sync frontend design skill - not a frontend project
skills/fed/
# Using custom auth, don't want template's supabase rules
rules/tech/supabase*.md
# Skip a specific workflow rule
rules/workflow/some-rule.md
Patterns:
- Glob patterns supported (
*.md,skills/*/) - Directory patterns should end with
/ - Comments start with
# - One pattern per line
When to use .syncignore:
- Project will never need certain template files
- Template files conflict with project-specific implementations
- Cleaner than repeatedly declining to add files
Report output:
Ignored (per .syncignore):
- skills/fed/ (per .syncignore)
- rules/tech/supabase*.md (per .syncignore)
Pruning Unused Rules
When technologies are removed from a project, the sync script identifies orphaned rules in the "Unused" section:
Unused (tech not detected):
- rules/tech/vue.md
- rules/tech/angular.md
Note: Remove unused rules manually if desired.
The script does not auto-remove files. When you see unused rules:
- Review the list - confirm the technology is truly no longer used
- If removing, use AskUserQuestion to confirm with the user:
Which unused rules should be removed?
- [ ] rules/tech/vue.md (vue not detected)
- [ ] rules/tech/angular.md (angular not detected)
- [ ] Keep all
- Remove confirmed files:
rm .claude/rules/tech/vue.md
Rules in rules/project/ are never flagged as unused - they're project-specific and not tied to technology detection.
Running the Script
~/.claude/skills/project-updater/update-project.sh
The script reports:
- Detected technologies (package.json, config files, directories)
- Detected tools (openspec)
- Changed - Files that differ, with timestamps and sync direction
- Added - Files missing from project
- Skipped - Files for undetected technologies/tools
- Protected - Files that need manual review (CLAUDE.md, _project.yaml)
- Unused - Rules in project for technologies no longer detected
- Hooks - Template hooks to add based on detected tools
Determining Sync Direction
The script compares file modification timestamps and shows direction for each changed file:
| Direction | Meaning | Action |
|---|---|---|
template is newer -> sync to project | Template was edited more recently | Copy template → project |
project is newer -> use /template-updater | Project was edited more recently | Skip (run /template-updater instead) |
Only sync files where the template is newer. Files where the project is newer should be pushed to the template via /template-updater, not overwritten.
Caveat: Timestamps are heuristic. Operations like git clone, git checkout, and cp without -p reset mtime to "now". When copying files, always use cp -p to preserve timestamps. When using Read/Write tools, the destination mtime will be "now" regardless — accept that the next sync report may show stale direction indicators.
After Running
Review the report and copy files where the template is newer:
# Read a file that needs updating
cat ~/.claude/template/rules/tech/nextjs.md
# Copy it to project (use -p to preserve timestamps)
cp -p ~/.claude/template/rules/tech/nextjs.md .claude/rules/tech/nextjs.md
Or use Claude's Read/Write tools to selectively copy files based on the report.
Protected Files
Never auto-updated (contain project-specific content):
CLAUDE.md- Project documentationagents-src/_shared.yaml- Project skill/rule configuration- Files with
<!-- PROJECT-SPECIFIC -->marker
Agent YAMLs
Agent definition files (agents-src/*.yaml except _shared.yaml) are synced from template. This keeps agent definitions generic across projects. Project-specific customization happens through:
_shared.yaml- Define which rules go in each bundle- Rule files - Create project-specific rules included via bundles
After Sync
Load the gitbutler skill first (/gitbutler), then commit the changes:
but status # Review changes
npm run build:agents # If agent YAMLs changed (script auto-adds npm script if missing)
but stage <file-id> <branch> # Stage changed files
but commit <branch> --only -m "chore: sync claude config"
Consider running /rules-review if:
- New tech rules were synced (verify no project content leaked into tech rules)
- Project has grown significantly since last review
- Rules feel disorganized or overlapping
Design Philosophy
Template files follow context-over-configuration:
- Skills/rules are generic and read from project context
- Syncing should "just work" without per-file decisions
- Tool-specific files only sync when that tool is enabled
- Only
_shared.yamlandCLAUDE.mdneed project customization