The Specific Situation
Your team’s generate-tests skill produces unit tests using Jest with a specific assertion style. You need to update it to also support Vitest, add integration test templates, and change the assertion format from expect().toBe() to expect().toEqual(). If you push this directly to main, every developer mid-session gets the new behavior instantly. A developer generating tests during a client demo suddenly gets a different output format. Here is how to update safely.
Technical Foundation
Claude Code watches skill directories and detects file changes in real time. When a SKILL.md is modified, the new content applies to all active sessions that discover the change. There is no versioning lock, no rollback button, and no “update available” notification. Changes are immediate and silent.
This live detection is powerful for personal iteration but dangerous for team-shared skills. Every file system change to .claude/skills/ is an instant deployment to everyone who has pulled the latest code.
The Working SKILL.md (Updated Version)
Before update (v1):
---
name: generate-tests
description: >
Generate unit tests for JavaScript files using Jest.
Use when the user says "write tests" or "add test coverage".
allowed-tools: Bash(npx jest *) Read
---
# Generate Tests (v1)
Generate Jest unit tests for $ARGUMENTS.
1. Read the source file
2. Create a test file in __tests__/
3. Use expect().toBe() for assertions
4. Run jest to verify tests pass
After update (v2):
---
name: generate-tests
description: >
Generate unit and integration tests for JavaScript/TypeScript
files using Jest or Vitest. Use when the user says "write tests",
"add test coverage", or "create integration tests".
version: 2.0.0
allowed-tools: Bash(npx jest *) Bash(npx vitest *) Read
---
# Generate Tests (v2)
## Changelog
- v2.0.0: Added Vitest support, integration tests, toEqual assertions
- v1.0.0: Initial Jest-only version
Generate tests for $ARGUMENTS.
1. Detect test runner (jest.config.* = Jest, vitest.config.* = Vitest)
2. Read the source file
3. Determine test type:
- Unit test: test individual functions in __tests__/
- Integration test (if user requested): test module interactions
in __tests__/integration/
4. Use expect().toEqual() for object assertions,
expect().toBe() for primitives
5. Run the detected test runner to verify tests pass
Safe Update Pattern: Feature Branch + PR
Never edit shared skills directly on main. Use the same workflow as code changes:
# Create a branch for the skill update
git checkout -b update-generate-tests-v2
# Edit the skill
# ... make changes to .claude/skills/generate-tests/SKILL.md
# Test locally (your session picks up changes immediately)
# Invoke /generate-tests and verify the new behavior
# Commit and push
git add .claude/skills/generate-tests/SKILL.md
git commit -m "feat: update generate-tests skill to v2 (Vitest, integration tests)"
git push -u origin update-generate-tests-v2
# Open a PR for team review
gh pr create --title "Update generate-tests skill to v2"
Team members review the PR like any code change. Only when merged does the skill change for everyone.
Gradual Rollout with Parallel Skills
For breaking changes, run old and new versions simultaneously:
.claude/skills/
├── generate-tests/ # Current stable (v1)
│ └── SKILL.md
└── generate-tests-v2/ # New version for testing
└── SKILL.md
The v2 skill has a different name (generate-tests-v2), so it does not replace v1. Early adopters use /generate-tests-v2 while everyone else continues with /generate-tests.
After validation, swap the directories:
mv .claude/skills/generate-tests .claude/skills/generate-tests-v1
mv .claude/skills/generate-tests-v2 .claude/skills/generate-tests
Keep v1 around for a sprint as a rollback option. Remove it once the team confirms v2 works.
Rollback Strategy
If an update breaks something:
# Immediate rollback via git
git checkout HEAD~1 -- .claude/skills/generate-tests/SKILL.md
git commit -m "revert: rollback generate-tests to previous version"
git push
Claude detects the file change and reverts to the old behavior. Developers with active sessions see the rollback within the same session – no restart needed.
Common Problems and Fixes
Update deployed mid-session breaks ongoing work: Claude loads skill content once per invocation. If a developer already invoked the skill before the file changed, they have the old version in their session. The new version loads on the next invocation. Mid-session disruption is unlikely but possible if they re-invoke.
Team members get different behavior: Usually caused by personal skill overrides. Run ls ~/.claude/skills/ on affected machines. Personal skills with the same name as the updated project skill shadow the update.
Rollback does not take effect: Git revert changes the file, but Claude needs to see the file system event. On some editors with atomic saves, the watcher may miss the event. Delete and recreate the file to force detection.
Cannot test the update without affecting the team: Use a parallel skill with a different name (generate-tests-v2). Or test on a feature branch – your local checkout has the changes but they do not affect main until merged.
Production Gotchas
The version field in frontmatter is informational only. Claude does not compare versions, check compatibility, or enforce upgrade paths. It is useful for human documentation but provides no automation.
Slack or Teams notifications for skill changes are not built in. Add a CI step that detects changes to .claude/skills/ and posts to your team channel. This prevents the “nobody noticed the skill changed” problem.
If a skill update changes the description field (trigger phrases), the skill may start firing on different requests or stop firing on previously matching requests. Test trigger matching explicitly after any description change.
Checklist
- Skill updates go through pull requests, not direct main edits
- Breaking changes use parallel skill directories for gradual rollout
versionfield updated in frontmatter- Changelog section in skill body documents what changed
- Rollback tested with
git checkout HEAD~1