Skip to content

feat(cli): add agent skill list and agent skill show commands#1230

Open
geoffjay wants to merge 2 commits into
issue-1211from
issue-1213
Open

feat(cli): add agent skill list and agent skill show commands#1230
geoffjay wants to merge 2 commits into
issue-1211from
issue-1213

Conversation

@geoffjay
Copy link
Copy Markdown
Owner

Adds two CLI subcommands for inspecting agent skills, implemented in a new commands/skill.rs module.

Commands:

  • agent skill list — formatted table with skill names and descriptions
  • agent skill list --json — JSON array of skill objects
  • agent skill show <name> — prints full Markdown content of a named skill
  • agent skill show <name> --json — full Skill struct as JSON

Discovery: Uses orchestrator::skills::discover_all_skills() directly — no service call needed since skills are filesystem-local to the project.

Closes #1213

geoffjay added 2 commits May 13, 2026 09:57
- 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 geoffjay added the review-agent Used to invoke a review by an agent tracking this label label May 13, 2026
Copy link
Copy Markdown
Owner Author

@geoffjay geoffjay left a comment

Choose a reason for hiding this comment

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

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_path correctly excluded from JSON: #[serde(skip)] on Skill.source_path (landed in #1226) means agent skill show git-spice --json produces 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 (via unwrap_or) and ensures the minimum 4-char column (via .max(4)).
  • Module registration: added to mod.rs in alphabetical order, re-exported correctly. ✓
  • --json on list: serde_json::to_string_pretty(&skills)? outputs the full Vec<Skill> array — source_path excluded, description included only when Some. 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.

@geoffjay geoffjay added merge-queue Approved by reviewer, queued for merge by conductor and removed review-agent Used to invoke a review by an agent tracking this label labels May 13, 2026
@geoffjay geoffjay linked an issue May 13, 2026 that may be closed by this pull request
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-queue Approved by reviewer, queued for merge by conductor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add agent skill list and agent skill show CLI commands

1 participant