Skip to content

fix(skill): invalidate skill cache when SKILL.md files change on disk#19136

Draft
jwm4 wants to merge 1 commit intoanomalyco:devfrom
jwm4:bugfix/issue-19050-skill-cache-invalidation
Draft

fix(skill): invalidate skill cache when SKILL.md files change on disk#19136
jwm4 wants to merge 1 commit intoanomalyco:devfrom
jwm4:bugfix/issue-19050-skill-cache-invalidation

Conversation

@jwm4
Copy link

@jwm4 jwm4 commented Mar 25, 2026

Issue for this PR

Closes #19050

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Skills are loaded once by ensure() in skill/index.ts and the result is cached as a resolved promise. Editing a SKILL.md file while opencode is running has no effect until restart because nothing clears that cache.

This fix adds an invalidate() function that resets the cached promise. It's triggered automatically when the existing FileWatcher detects a change to any SKILL.md file. The Command service also subscribes to a new Skill.Event.Invalidated bus event so slash commands pick up the fresh content.

Two source files changed, one new test file added:

  • packages/opencode/src/skill/index.ts — cache invalidation + file watcher subscription
  • packages/opencode/src/command/index.ts — subscribe to skill invalidation to rebuild commands
  • packages/opencode/test/skill/skill-stale-cache.test.ts — 4 regression tests

How did you verify your code works?

  • 4 new regression tests that modify SKILL.md on disk and call invalidate(), then verify Skill.list() returns updated content (edit, add, delete scenarios)
  • All 11 existing skill tests pass
  • All 9 skill tool tests pass
  • Full test suite: 1468 pass, 0 fail, 17 skip
  • Type checking passes (bun turbo typecheck)

Screenshots / recordings

N/A — no UI changes.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Skills were loaded once at startup and cached permanently — editing a
SKILL.md file while opencode was running had no effect until restart.

Add cache invalidation triggered by the existing FileWatcher infrastructure:
- Skill cache clears when a SKILL.md file changes (via Bus subscription)
- Command cache rebuilds when skills reload (via Skill.Event.Invalidated)
- Expose Skill.invalidate() for programmatic use

Fixes anomalyco#19050

## Summary
- Fix skill cache not invalidating when SKILL.md files are edited on disk
- Add `Skill.Event.Invalidated` bus event for cross-service coordination
- Invalidate Command cache when skills reload so slash commands reflect changes

## Test plan
- [x] 4 new regression tests (edit, get, add, delete)
- [x] All 11 existing skill tests pass
- [x] Full test suite: 1468 pass, 0 fail
- [x] Type checking passes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added needs:compliance This means the issue will auto-close after 2 hours. and removed needs:compliance This means the issue will auto-close after 2 hours. labels Mar 25, 2026
@github-actions
Copy link
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@github-actions
Copy link
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • Not all checklist items are checked. Please confirm you have tested locally and have not included unrelated changes.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

Copy link
Author

@jwm4 jwm4 left a comment

Choose a reason for hiding this comment

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

Manual testing feedback

The cache invalidation plumbing works correctly — Skill.invalidate() clears the cache and the next Skill.all()/Skill.get() call re-reads from disk. The automated tests all pass.

However, there's a significant gap in the end-to-end flow: the fix only works when OPENCODE_EXPERIMENTAL_FILEWATCHER=true is set, which most users won't have enabled.

The PR subscribes to FileWatcher.Event.Updated to detect SKILL.md changes, but FileWatcher only watches Instance.directory when the experimental flag is on (see src/file/watcher.ts:123). Without it, only the .git directory is watched — so FileWatcher.Event.Updated never fires for SKILL.md changes, and the cache is never invalidated.

This means the original issue (#19050) remains unfixed for the default configuration.

Additional note

Even with the experimental flag enabled, the FileWatcher only watches Instance.directory (the CWD). In monorepo setups, skills loaded from parent .opencode/ directories (found via Filesystem.up) won't trigger invalidation when edited, since the watcher doesn't cover those parent directories.

Suggestions

  1. Consider an approach that doesn't depend on OPENCODE_EXPERIMENTAL_FILEWATCHER — e.g., a dedicated watcher for skill directories, or polling skill files for changes.
  2. If sticking with FileWatcher, the watcher scope should cover all directories returned by Config.directories() and the external skill dirs, not just Instance.directory.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SKILL reference not update after edit the SKILL

1 participant