Skip to content

feat(agent-core-v2): watch user-level skill roots so the catalog stays fresh - #3608

Merged
wbxl2000 merged 2 commits into
mainfrom
feat/watch-user-skill-roots
Sep 7, 2026
Merged

feat(agent-core-v2): watch user-level skill roots so the catalog stays fresh#3608
wbxl2000 merged 2 commits into
mainfrom
feat/watch-user-skill-roots

Conversation

@liukx0205

Copy link
Copy Markdown
Collaborator

Problem

Skills created in the user-level skill directories (~/.kimi-code/skills, ~/.agents/skills) while the daemon is running are not visible to any session: UserFileSkillSource only re-scans those directories when the workspace skill catalog is (re)loaded, which in practice means a daemon restart. The project-level roots did not have this problem — WorkspaceRootSkillSource watches the project root and reloads on change.

What changed

Mirror the project-level watch pattern in UserFileSkillSource:

  • Watch both user-level base directories: bootstrap.homeDir (KIMI_CODE_HOME, covering skills/) and bootstrap.osHomeDir (covering .agents/skills/), each with a subtreeWatchFilter that prunes everything outside the skill-root candidates so the rest of the home directory is neither traversed nor reported.
  • Change events are debounced (200ms, same as the workspace source) and fire onDidChange, which makes WorkspaceSkillCatalogService reload the 'user' source — so GET /sessions/{id}/skills is always fresh.
  • load() awaits watch readiness (same race-avoidance as the workspace source), and the watch handles are registered on the service's DisposableStore, so they are disposed with the App scope.
  • When explicit skillDirs are configured the user source is inactive, so no watches are installed.

Tests in packages/agent-core-v2/test/features/skill/workspace/skillCatalog.test.ts: watch registration and filter pruning for both roots, no watches with explicit skillDirs, disposal with the App scope, and an end-to-end real-watcher test that creates / modifies / deletes a SKILL.md under tmpdir home roots (including .agents/skills) and asserts the catalog updates after the debounce.

Relationship to #3597

This supersedes #3597 (POST /sessions/{id}/skills:reload): with the catalog kept fresh by the watcher, no reload endpoint is needed.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: the issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

Verified locally: agent-core-v2 skill feature tests (135 tests) and the broader test/features test/app test/workspace test/session suites (2716 tests), kap-server skills tests (20 tests), tsc --noEmit for both packages, and repo-wide oxlint --type-aware (0 errors).

…s fresh

UserFileSkillSource previously only re-scanned the user skill roots
(KIMI_CODE_HOME/skills and ~/.agents/skills) on catalog load, so a skill
created while the daemon was running never appeared until a restart.

Mirror the workspace-root source: watch both user-level base directories
with a subtree filter limited to the skill-root candidates, debounce
(200ms) change events, and fire onDidChange so the catalog reloads the
'user' source automatically. Watch handles are registered on the
service's DisposableStore and disposed with the App scope.

Supersedes the skills:reload endpoint approach (#3597).
@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 917eec4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Sep 7, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@917eec4
npx https://pkg.pr.new/@moonshot-ai/kimi-code@917eec4

commit: 917eec4

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31c14d1fb5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/agent-core-v2/test/features/skill/workspace/skillCatalog.test.ts Outdated
Comment thread packages/agent-core-v2/src/features/skill/catalog/userFileSkillSource.ts Outdated
Comment on lines +87 to +89
const handle = watch(base, {
ignored: subtreeWatchFilter(base, candidates),
signal: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Watch resolved user skill roots behind symlinks

On the chokidar-backed platforms, this watches only the parent base while the shared watcher is configured with followSymlinks: false. If skills or .agents/skills is a symlink—common when managing home configuration through a dotfiles directory—initial discovery succeeds because userRoots() resolves the symlink, but subsequent edits in its target produce no event and the catalog remains stale; the resolved discovered roots also need watcher coverage.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

确认为已知边界,本 PR 不修复。followSymlinks: false 是共享 watch 基础设施(#human/utils/watch)的统一配置,项目级 WorkspaceRootSkillSource 对符号链接的 .agents/skills 也存在同样限制,并非本 PR 引入的回归。正确修法是在每次 load 后对 realpath 出的 scannedRoots 轮换 watch(类似项目级的 watch handoff),属于基础设施增强,影响面限于用 dotfiles 符号链接管理 skills 目录的用户(重启/重载后首次扫描仍正常)。建议记录为后续 issue。

— Mira(代 liukx0205 分诊处理)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Acknowledged as a known boundary, not fixing in this PR. followSymlinks: false is the shared watch infrastructure's uniform setting (#human/utils/watch), and the project-level WorkspaceRootSkillSource has the same limitation for symlinked .agents/skills — not a regression introduced here. The proper fix is rotating watches onto the realpath-d scannedRoots after each load (similar to the project-level watch handoff), which is infrastructure-level work. Impact is limited to dotfiles-symlinked skill dirs, and the initial scan on (re)load still resolves symlinks correctly. Suggest tracking as a follow-up issue.

…mments

Codex review on #3608:

- When KIMI_CODE_HOME equals the OS home dir, deduplicating watch bases
  skipped the .agents/skills candidate entirely. Group candidates by
  base instead so one watch covers both roots.
- Remove // phase labels from the catalog test: agent-core-v2 is a
  comment-free zone enforced by scripts/check-no-comments.mjs (lint was
  red on CI).
@wbxl2000
wbxl2000 merged commit fb0353a into main Sep 7, 2026
15 checks passed
@wbxl2000
wbxl2000 deleted the feat/watch-user-skill-roots branch September 7, 2026 09:41
@github-actions github-actions Bot mentioned this pull request Sep 7, 2026
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.

2 participants