feat: skills plugin #210
No reviewers
Labels
No labels
Compat/Breaking
Kind/Bug
Kind/Competitor
Kind/Documentation
Kind/Enhancement
Kind/Epic
Kind/Feature
Kind/Security
Kind/Story
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Scope/Core
Scope/Cross-Plugin
Scope/Plugin-System
Scope/Single-Plugin
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ultanio/cobot!210
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "David/cobot:feature/skills"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds a Skills plugin that brings markdown-based skill management to cobot — discover, install, load, and remove reusable agent skills from local paths or git repos.
Includes 639 lines of tests covering discovery, frontmatter parsing, CLI commands, and edge cases.
Implements #207
feature/skillsto feat: skills pluginReview: Skills Plugin
Great work David — this is a solid, well-structured plugin. Clean separation (models, cli, plugin), proper ToolProvider pattern, good test coverage (639 lines!). Here's my detailed feedback:
✅ Architecture Strengths
Skilldataclass + pure utility functions inmodels.pyload_skillfollows established cobot conventionsloop.transform_system_prompt— correct hook🟡 CLI Verbosity (your question)
You're right — the
click.echolines incli.pyare verbose. Options:_print_skill(skill)and_print_skill_list(skills)function that handles the formatting. Reduces repetition.click.echowith f-strings is actually fine — it's explicit and readable. The verbosity is mostly inskill_showwhich has ~8 echo calls. That's not bad.My take: extract a
_format_skill_detail(skill) -> strthat returns the whole block, thenclick.echo(_format_skill_detail(match)). One echo call instead of 8. Same for list.🔴 Git dependency (your question)
The git-only approach for
skill addis fine as-is. Here's why:gitis ubiquitous on dev machines"git is required for remote skill installation"One improvement: Add a note to the error message:
This guides Docker users to the working alternative.
🟡 Code Issues
_discover_and_list()duplicates_discover_skills()— 90% same code. Extract shared logic into_scan_paths(skip_disabled=True)that both call.register_plugin_commands()change incli.py—registry.register(plugin_class)changed fromregistry.register(instance). Is the registry API actuallyregister(class)orregister(instance)? Verify this doesn't break other plugins.BMad artifacts in
.gitignore—_bmad/**and_bmad-output/**plus.claude/commands/**and.cursor/commands/**added. These are editor/workflow specific. Consider putting them in.git/info/excludeinstead of polluting the shared.gitignore.No error handling on
shutil.copytreein_install_single_skill— if target dir has permission issues, it'll crash with a raw traceback.resolve_relative_pathsregex — only matches./foo/bar.mdpatterns. Won't resolve../paths or paths without extensions. Fine for now, but document the limitation.🟢 Tests
Excellent coverage — 639 lines of tests. Models, plugin, CLI helpers all covered. Only gap: no integration test for
_install_from_git(understandable, requires network).Summary
This is merge-ready with minor fixes:
_discover_and_list()vs_discover_skills().gitignoreregistry.register()API changeOverall: excellent plugin, well-designed. 👏
The API is unambiguous:
The old code was instance = plugin_class() then registry.register(instance) — passing an object to a method that expects a class. Line 78 would always fail because an instance is not a type. This was a pre-existing bug affecting all plugins, not just skills — we saw every single plugin fail with the same error in Docker.
Re-review ✅
All previous issues addressed:
_scan_all_paths()extracted, both_discover_skills()and_discover_and_list()use it.gitignoreregister(class)is the correct signature, old code was wrongLGTM — ready to merge. 👍
CI lint failure:
cobot/plugins/skills/cli.pyneeds formatting.Fix:
ruff format cobot/plugins/skills/cli.pyLinzer is red, though.
@k9ert can you / nazim review again, linter is fine now
doxios referenced this pull request2026-03-08 16:28:27 +00:00