Skip to content

feat(core): live skills in the V2 session core — watcher-driven cache invalidation (#1740, partial) - #1852

Draft
aarontrowbridge wants to merge 4 commits into
mainfrom
live-skills-watch
Draft

aarontrowbridge wants to merge 4 commits into
mainfrom
live-skills-watch

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

Part of #1740.

What it does

  • core/src/skill.ts (V2): subscribes to Watcher.Event.Updated on the EventV2 bus. Changed files are marked immediately, and a 50ms-debounced flush drops the cache entry of every source whose directories contain a changed file, so the next list() re-globs it.
  • core/src/tool/skill.ts (V2): the skill body is re-read from disk on each invocation. If the read fails, it falls back to the cached body.
  • opencode/src/skill/index.ts (V1): a comment documenting that this path stays boot-frozen.

Why it's a draft: it doesn't reach the fleet yet

The fleet's sessions run on the V1 path. opencode/src/tool/skill.ts and session/system.ts import the V1 Skill service, which loads once per instance and is never re-read. So this PR does not make skill edits visible to running hub sessions, which is #1740's motivating problem (every skill fix needs a hub restart). To close #1740, the V1 Skill discovered/state InstanceStates need the same invalidation, either from watcher events under the discovered skill dirs or from a cheap fingerprint check like #1850's auth.json stamp.

Tests

core/test/skill.test.ts + core/test/tool-skill.test.ts: 12/0 on a fresh materialize at current main.

The per-Location skill parse cache invalidates on filesystem watch events:
the consumer subscribes to the existing Location-scoped watcher's bus events,
marks changed files immediately, and flushes debounced (50ms) — dropping the
cache entry of every source whose directories contain a changed file so the
next list() re-globs it. Reloads stay lazy and coalesced; a consumer failure
logs and degrades to the boot-frozen behavior. Tests cover invalidation,
add/unlink of skill directories, burst coalescing, disposal, the fail-safe
floor, and delivery through the SystemContext + SessionContextEpoch
machinery (ContextUpdated event on a real db session).
The skill tool serves the SKILL.md body from disk at invocation time via a
new SkillTool.liveContent seam, matching its fresh companion-file glob — the
parse cache only pins name/description metadata between watcher
invalidations. A failed read falls back to the cached body, never a tool
failure.
The v1/TUI skill cache stays deliberately boot-frozen — InstanceState
loads once per directory and never re-reads. Live watcher-driven
invalidation ships in the V2 session core only; document that boundary
honestly at the code site so no silent parity is claimed.
The debounced flush lands asynchronously; poll the observable outcome with a
5s bound instead of fixed 200ms sleeps so the tests stay green under a loaded
shared bun process. The reload is lazy, so the polls drive list() — a fixed
sleep never observes the re-glob on its own.
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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.

feat(engine): live skills — watcher-driven cache invalidation + per-invocation content re-read

1 participant