One Friday night, I changed a single line in a skill I use for scheduled runs. A small tweak to the log output format, nothing more. The next morning, the logs showed the run had followed the old spec. The file was saved correctly — but Claude Code had been reading "yesterday's SKILL.md."
If you run several automation tasks off SKILL.md files as an indie developer, this "I fixed it but nothing changed" moment happens more often than you would expect. The cause is when skills get loaded, not what you wrote. Recent versions of Claude Code added auto-loading for skills under .claude/skills and a /reload-skills command, which together make restart-free swaps possible. Here is the routine I settled on in day-to-day operation, along with the trap that makes a reload look like it "didn't work."
SKILL.md Is Read at Session Start
A skill lives in a Markdown file, but Claude Code consults that file primarily when a session begins. At startup it builds an index of skill names and descriptions, and then expands the body of a matching skill when a task calls for it — a two-stage process.
That means editing a SKILL.md while a session is running leaves that session's index untouched. From the outside it feels like your file is being ignored; in reality, the session keeps referencing a snapshot it already loaded. This is exactly why a restart "fixes" it.
For the design side of skills themselves, see Claude Code Custom Skill Development Patterns — SKILL.md Design, Testing, and Distribution.
Auto-Loading from .claude/skills Removed the Distribution Step
Skill distribution used to assume a plugin or marketplace flow, which always felt heavyweight for personal working skills. Now, anything placed under a project's .claude/skills directory is auto-loaded with no marketplace involved.
I took this change as a cue to keep the canonical copies of my skills in a Git repository and sync them into each project's .claude/skills. A skill is both a prompt and an operations runbook, and Git's diff history suits that dual nature better than I expected. Simply being able to trace when an instruction changed, and how, cut down the time I spend asking "why did it produce this output?"
What /reload-skills Actually Covers — It Applies from the Next Invocation
To swap a skill without ending the session, run /reload-skills. Edit, reload, and the next invocation uses the new version.
There is one detail the official description won't make obvious. A reload refreshes the skill index and the body that will be expanded next time — but any skill body already expanded earlier in the session stays in context. Reload midway through a long session and you end up with old and new instructions coexisting, with no easy way to tell which one a given output followed.
So my rule is to reload only at task boundaries. Finish the work in flight, run /reload-skills, then start the next piece of work fresh. That single habit has all but eliminated mixed-instruction confusion for me.
Unattended Runs: Pull the Latest via a SessionStart Hook
In unattended setups like scheduled runs, nobody is around to type /reload-skills. This is where the SessionStart hook earns its keep: run your skill sync at session start and return reloadSkills: true from the hook output, and the freshly pulled skills are what gets loaded.
The script below syncs my canonical skills repository before loading:
#!/bin/bash
# .claude/hooks/session-start-sync.sh
# Sync the canonical skills repo before skills are loaded
git -C "$HOME/dev/skills-repo" pull --rebase --quiet
rsync -a --delete "$HOME/dev/skills-repo/skills/" ".claude/skills/"
echo '{"reloadSkills": true}'Register it in settings.json like this:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/session-start-sync.sh"
}
]
}
]
}
}One caveat if you distribute skills through cloud-storage sync: if a session starts before the sync finishes, only the old version exists locally. The hook can only read what is on disk at that moment, so this gap cannot be closed by machinery alone — I catch it with the version-stamp check described next.
For the broader unattended-execution design, see Designing Claude Code Skills for Unattended Runs — Three Patterns That Avoid Permission-Dialog Stalls.
Make the Live Version Visible with a Version Stamp
What truly ended my "I fixed it but nothing changed" episodes wasn't the reload machinery — it was making the live skill version visible in the logs. It takes two steps.
First, put a version stamp in a comment at the top of the SKILL.md:
<!-- version: 2026-06-13.1 -->
# article-publisherSecond, make the first step of the skill's procedure print that line into the run log:
grep -m1 'version:' .claude/skills/article-publisher/SKILL.mdEvery run now starts its log with the version it actually executed. When behavior looks stale, check the stamp first: an old stamp means a sync or reload problem, while a new stamp with old behavior means the instructions themselves need work. The triage becomes a straight line. Since adding these two lines, I have never had to guess whether an edit "should have" taken effect.
Your Next Step — Add One Version Line
Before memorizing the mechanics of /reload-skills and SessionStart hooks, make the live version observable. Add a single version line to a SKILL.md you use today and print it in your run logs — the reload timing behavior becomes dramatically easier to watch. For how I decide which skills earn a permanent place in my workflow, see The 5 Criteria I Use When Folding Claude Code Skills into Daily Development. If you run SKILL.md-driven automation of your own, I hope this routine saves you a morning of confusion.