feat(cli): add agent skill list and agent skill show commands#1230
feat(cli): add agent skill list and agent skill show commands#1230geoffjay wants to merge 2 commits into
Conversation
- New crates/cli/src/commands/skill.rs with SkillCommand enum - agent skill list: discovers and displays skills with name/description columns - agent skill list --json: outputs JSON array - agent skill show <name>: prints full skill Markdown content - agent skill show <name> --json: outputs full Skill struct as JSON - Clear error when named skill is not found - Re-exported SkillCommand from commands/mod.rs - Wired into Commands enum and dispatch in main.rs Closes #1213
geoffjay
left a comment
There was a problem hiding this comment.
Review: feat(cli): add agent skill list and agent skill show commands
Stack Position
Branch issue-1213 is stacked on issue-1211 (PR #1229). Full chain: main ← epic-1209 ← issue-1210 ← issue-1211 ← issue-1213. All parent PRs (#1226, #1228, #1229) are now in merge-queue.
No Blocking Issues
Non-Blocking: execute() Is async but Delegates to Sync Functions
pub async fn execute(&self, json: bool) -> Result<()> {
match self {
SkillCommand::List => list_skills(json),
SkillCommand::Show { name } => show_skill(name, json),
}
}Both list_skills and show_skill are plain fn, not async fn. The async on execute is harmless — calling a sync fn from an async context is fine — but it implies await points exist when there are none. Other commands need async because they make HTTP calls; this one doesn't. Minor inconsistency, not blocking.
Non-Blocking: Table Output Has No Column Header
agentd Skills
============================================================
git-spice Branch stacking and PR management.
linting Run clippy and fmt.
The column width is computed correctly (adapts to the longest skill name, minimum 4), but there's no header row labeling the columns. A simple addition would help users who see only one or two skills:
println!(" {:<width$} {}", "NAME".bold(), "DESCRIPTION".bold(), width = name_width);
println!(" {}", "-".repeat(name_width + 2 + 40));The separator line at "=".repeat(60) is currently fixed-width while the columns are dynamic — they can diverge for very long skill names. Non-blocking, but worth tidying.
Non-Blocking: Tests Are Compile-Time Stubs Only
#[test]
fn test_skill_command_list_variant_exists() {
let _cmd = SkillCommand::List;
}These only verify the enum compiles. No tests cover the formatted output, the bail! path for an unknown skill name, or the JSON serialization path. Consistent with test coverage being deferred to #1214 — just noting it.
What's Working Well
- Direct library call is the right design:
orchestrator::skills::discover_all_skills()instead of an HTTP call correctly recognizes that skill discovery is filesystem-local. No round-trip to the service, no latency. source_pathcorrectly excluded from JSON:#[serde(skip)]onSkill.source_path(landed in #1226) meansagent skill show git-spice --jsonproduces clean output without server filesystem paths — no extra work needed here.- Actionable error message:
bail!("Skill '{}' not found. Run 'agent skill list' to see available skills.", name)is the right pattern — users don't need to know the discovery algorithm to fix the problem. - Column width adapts dynamically:
skills.iter().map(|s| s.name.len()).max().unwrap_or(4).max(4)correctly handles empty skill lists (viaunwrap_or) and ensures the minimum 4-char column (via.max(4)). - Module registration: added to
mod.rsin alphabetical order, re-exported correctly. ✓ --jsononlist:serde_json::to_string_pretty(&skills)?outputs the fullVec<Skill>array —source_pathexcluded,descriptionincluded only whenSome. Correct.
Summary
No blocking issues. The three non-blocking notes are: async on execute is unnecessary since discovery is synchronous, the table output lacks a column header, and tests are compile-time stubs (expected, deferred to #1214). The core design — direct library call for filesystem-local skill discovery — is correct and consistent with the codebase architecture. Parent chain is fully in merge-queue.
Adds two CLI subcommands for inspecting agent skills, implemented in a new
commands/skill.rsmodule.Commands:
agent skill list— formatted table with skill names and descriptionsagent skill list --json— JSON array of skill objectsagent skill show <name>— prints full Markdown content of a named skillagent skill show <name> --json— full Skill struct as JSONDiscovery: Uses
orchestrator::skills::discover_all_skills()directly — no service call needed since skills are filesystem-local to the project.Closes #1213