-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add /skills panel: browse, invoke, open, and delete loaded skills - #1289
Add /skills panel: browse, invoke, open, and delete loaded skills #1289lab1207 wants to merge 7 commits into
Conversation
cli/bunfig.toml lists test/setup-scm-loader.ts among its preloads, but the file was never exported to the public mirror. Any test reaching the SDK barrel (which re-exports code-map, which imports .scm tree-sitter query files) threw "Unknown file type" at import time, which bun surfaces as an unhandled error between tests — a fresh clone showed a wall of dead test files with no obvious cause. The plugin registers a bun loader that imports .scm files as a default-exported string, matching what the bundled build does. Verified against the CLI suite: 1,576 pass, with only the pre-existing Windows-path failures in export-conversation.test.ts remaining (unrelated). 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Skills already load from ~/.agents/skills/ and .agents/skills/ and run as /skill:<name>, but the CLI had no surface answering "what do I have?". Project skills silently shadow global ones, and removing a skill meant hunting down files by hand. /skills (alias /skill) opens a panel cloning the queue-panel pattern: - rows show each skill's source (project vs global) and description - Enter invokes via the existing skill input mode (same path as /skill:<name>, shared through enterSkillMode, so entries can't drift) - o opens the SKILL.md in $EDITOR; d deletes with confirmation - empty registry prints install guidance (npx skills add ...) instead of opening an empty panel The keymap lives in utils/skills-panel-actions.ts, testable without a renderer like queue-panel-actions. Panel participates in the same keyboard/dock arbitration as the queue panel (review, ask-user, sponsored menu). One deviation from queue-panel: the confirm state swallows all other keys, so a held d can't chain-delete rows. Includes test/setup-scm-loader.ts (cherry-picked) — the preload bunfig.toml references but the mirror lacked; without it, tests touching the SDK barrel die at import. Verified: new tests pass (9), CLI suite 1,586 pass / 12 fail, all 12 pre-existing Windows-path/locking failures present on main. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Skills were frozen at startup: a skill installed mid-session was invisible until restart, and deleting from the /skills panel never removed the row because the component read a one-time useMemo snapshot. The registry now refreshes with content diffing and a version number that React subscribes to, skill directories are watched so changes land within the session, and the panel refreshes on open and after a delete. Frontmatter parity with Claude Code: user-invocable: false hides a skill from the / menu, when_to_use is appended to the agent's skill listing, and argument-hint is tolerated (coerced from the YAML list its unquoted docs form parses into). Deleting a skill now removes its directory rather than only SKILL.md, so supporting files are not orphaned, and the project/global badge derives from resolveSkillsDirs (now exported from the SDK) instead of a HOME string check that misclassified on Windows. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
The ponytail skills (built for Claude Code, Codex, and Copilot) are installed by the skills CLI into ~/.claude/skills and must load in Freebuff unmodified for the cross-platform promise to hold. The test runs all six through the SDK loader and asserts name, description, content, and source path survive. Skips where the package is not installed so CI stays green. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
Rows now show a right-aligned ~token estimate (chars/4, k-abbreviated past 999) so users can see what each skill costs their context, and `/` enters a search mode that filters by name/description while keeping arrows/enter live; letters type instead of firing shortcuts, esc exits, backspace on an empty query exits too. Helpers live in renderer-free skills-panel-format.ts. Also fixes the two skill-registry live-reload tests, which passed only on machines without Claude Code skills: includeHomeSkills loaded the real ~/.claude/skills into the counts (7 != 1 with ponytail installed). Tests now redirect HOME/USERPROFILE into the tmp dir, making them hermetic. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
The footer promised "esc clears" the filter, but while browsing escape closed the panel — the filter could only be cleared by backspacing in search mode. Escape now unwinds one layer at a time: search mode → active filter → close, with a footer hint that changes to "esc clears filter · esc again closes" while a filter is active. q and ctrl+c still close directly. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
codebuff-team
commented
Sep 6, 2026
The core idea — a /skills panel that mirrors the queue-panel architecture (skills-panel-store.ts, skills-panel-actions.ts, skills-panel.tsx) — is well-factored: the keymap resolver is renderer-free and unit-tested (skills-panel-actions.test.ts), and reusing enterSkillMode for the Enter action correctly avoids duplicating the invoke path. That part alone (~600 lines) would be reviewable and worth porting.
But the PR grew mid-flight (see the "Update" section in the body) to also add a filesystem watcher for live skill reload, which is a second, independently-testable feature bolted onto the first. Two concerns there:
-
startSkillDirWatcherinskill-registry.tscallswatch(dir, { persistent: false }, ...)without{ recursive: true }. Skills live at<skillsDir>/<name>/SKILL.md— a subdirectory of the watched path. Non-recursivefs.watchon Linux only fires for changes to entries directly inside the watched directory (new/removed subdirectories), not for edits to files nested one level down inside an existing subdirectory. So the claimed "edited" case in "installed, edited, or deleted" is very likely silently broken on Linux, and the included test (watcher picks up an install without restart) only exercises the create-new-directory case, which is exactly the case that still works withoutrecursive: true. This needs a real edit-in-place test and, likely, a recursive watch or a supplementary poll/re-stat. -
ponytail-compat.test.tsdepends on an external, personally-installed skill repo anddescribe.skipIf(!installed)s itself out in CI. It provides no CI signal and bakes in a private dependency and file layout assumption not in this repo — this doesn't belong in the PR regardless of the panel's quality.
At 1615/-16 across 20 files with two feature sets stitched together, this is too large a unit for a maintainer to safely port and review as one change. Recommend splitting into (a) the panel/store/keymap PR, tested as it is, and (b) a live-reload PR with a real recursive-watch fix and an edit-in-place test.
Per review on CodebuffAI#1289: the filesystem watcher is an independently reviewable feature and moves to its own PR (recursive-watch semantics differ per platform). The panel keeps its refresh-on-open and refresh-after-delete behavior, which covers installs and edits without any watcher. Also drops ponytail-compat.test.ts (external dependency, no CI signal). 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
lab1207
commented
Sep 6, 2026
Thanks for the thorough review — the watcher criticism is correct and the
split is done.
This PR is now the panel only. fec7943 removes
startSkillDirWatcher/stopSkillDirWatcher from skill-registry.ts, the
watcher call from index.tsx, and the watcher test — and drops
ponytail-compat.test.ts entirely (you're right that an externally-gated
test with no CI signal and a private layout assumption doesn't belong).
The panel keeps refresh-on-open and refresh-after-delete, so installs,
edits, and deletes are all still picked up without a restart; only the
mid-session automatic notification went away, and that comes back with the
second PR below.
On the watch bug itself — you were right, and the fix was simpler than
poll. Bun's fs.watch supports recursive: true on Linux (rewritten
watch backend in bun 1.3), and Node has supported it there since 19.1. On
feat/skills-reload (already pushed) the watcher passes
{ persistent: false, recursive: true } — skills live one level down, so
the non-recursive form genuinely could never see a SKILL.md edit on
Linux, exactly as you said. That branch also adds the missing
edit-in-place test: it rewrites SKILL.md inside an existing skill
directory (no new directory, no rename at the watched level) and asserts
the registry version bumps and the new description loads. The old test's
create-new-directory case was indeed the only one that worked without the
flag.
Sequencing: the reworked watcher lives on the fork branch
feat/skills-reload, whose diff vs this PR's branch is exactly the watcher
files (+131/−6). I'll open it as a PR against main once this PR is ported
and the port lands on the public mirror — from then on its diff shows only
the watcher delta. If you'd rather carry it as one change, happy to have it
squashed in at port time instead.
What
A /skills slash command (alias /skill) that opens an interactive panel for
managing loaded skills — the management surface skills currently lack. Follows
the issue discussion on skill discoverability: project skills silently shadow
global ones, and there is no in-CLI answer to "what do I have?" short of
reading directories.
Closes none — related to the /skills feature proposal. (Also includes
test/setup-scm-loader.ts, cherry-picked from my earlier PR, because tests
touching the SDK barrel cannot run without it.)
UX
path /skill: takes — shared via enterSkillMode so the two entries
can't drift)
npx skills add <owner/repo>) instead of an empty panelImplementation
Clones the queue-panel architecture end to end:
like queue-panel-actions
(render branch, keyboard-disable, dock takeover, unmount cleanup)
Panel participates in the same keyboard arbitration as queue (review,
ask-user, sponsored menu). One deliberate deviation from queue-panel: while a
delete is pending confirmation, all other keys are swallowed so a held
dcannot chain-delete rows — a risk the queue editor doesn't have.
Verification
path-separator and file-locking failures present on main. Happy to file
separate issues for those.
Tested on Windows 11 / bun 1.3.14.
Update: live reload + Claude Code parity
After studying Claude Code's skills implementation, this PR now also:
are watched, so skills installed, edited, or deleted mid-session appear
without a restart. This also fixes a bug the original PR had: the skills
list was a frozen startup snapshot, so deleting from the panel never
removed the row. The registry now refreshes with content diffing and a
version that React subscribes to; the panel refreshes on open and after a
delete. Agent runs already re-read skills from disk per run, so the model
sees new skills immediately too.
user-invocable: false(model-only skills are hidden from the / menu, as in Claude Code) and
when_to_use(appended as trigger context in the agent's skill listing).argument-hintis tolerated. One real-world catch: Claude Code's docswrite
argument-hint: [issue-number]unquoted, which YAML parses as alist — we coerce it back to the display string rather than rejecting the
whole skill.
skill" semantics, so skills with supporting files (reference docs,
scripts/) are not half-deleted.
paths (
resolveSkillsDirs, now exported from the SDK) instead of a HOMEstring check that misclassified on Windows.
Verification: +11 tests (frontmatter parsing incl. the YAML coercion, XML
formatting, registry refresh/diff/version/watcher), all pass on Windows /
bun 1.3.14. CLI suite unchanged vs. baseline (only the pre-existing Windows
path-separator and file-locking failures).
Real-world compatibility check: installed the ponytail skill package
(github.com/DietrichGebert/ponytail — built for Claude Code / Codex /
Copilot) via
npx skills add DietrichGebert/ponytail -g -a claude-codeandloaded all 6 of its skills through Freebuff's SDK loader
(ponytail-compat.test.ts): every skill parses with name/description/content
intact from ~/.claude/skills, no modification needed.
Update: panel v2 — token estimates + search filter
Two additions to the /skills panel, borrowed from Claude Code's panel where
they fit our complementary scope (theirs toggles enable/disable; ours
invokes, opens, and deletes — see thread below):
Token estimates per row. Each row now ends with a right-aligned
~token readout (
~524 tokstyle, chars/4,knotation past 999) so youcan see what each skill costs your context window before invoking.
Deliberately an estimate — the point is relative weight, not an exact
count. Helpers are renderer-free (
skills-panel-format.ts) andunit-tested alongside the keymap, following the same pattern as
skills-panel-actions.ts./search filter. Pressing/opens an inline query that filtersthe list by name/description as you type. While searching, letters edit
the query —
d,o,qfire no shortcuts underneath your typing —while arrows/enter still navigate and invoke. Escape unwinds one layer
at a time: search mode → active filter → close the panel. A muted
"N hidden by filter" line shows what the query excludes, and the footer
hint switches to "esc clears filter · esc again closes" while filtered.
Live run on Windows 11 with the six ponytail skills installed via
npx skills add DietrichGebert/ponytail -g -a claude-code(the same onesfrom the compat test in the previous update):
previous update failed on any machine with Claude Code skills installed —
includeHomeSkillsloaded the real~/.claude/skillsinto the expectedcounts (7 != 1 with ponytail present). They now redirect HOME/USERPROFILE
into the temp dir, making them hermetic for any developer's machine and
CI.
Verification: +12 tests (search keymap incl. the escape-unwind chain,
token formatting, filter matcher, hermetic registry watcher), 25/25 across
the skills test files, typecheck clean, full CLI suite unchanged from the
documented pre-existing Windows baseline.