Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/HELP.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,16 @@ List recent scans for a repository

Install Detail skills (default: detail-bugs)

**Usage:** `detail skill [COMMAND]`
**Usage:** `detail skill [OPTIONS] [COMMAND]`

###### **Subcommands:**

* `rules` — Install the detail-create-rules skill

###### **Options:**

* `--user` — Install to user-level ~/.claude/skills instead of the current repo



## `detail skill rules`
Expand Down
29 changes: 22 additions & 7 deletions src/commands/skill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::str;

use anyhow::{Context, Result};
use clap::Subcommand;
use homedir::my_home;

const BUGS_SKILL_CONTENT: &str = include_str!("../../.claude/skills/detail-bugs/SKILL.md");
const RULES_SKILL_CONTENT: &str = include_str!("../../.claude/skills/detail-create-rules/SKILL.md");
Expand All @@ -22,14 +23,19 @@ fn parse_git_root_output(success: bool, stdout: &[u8]) -> Result<PathBuf> {
Ok(PathBuf::from(root.trim()))
}

fn skill_install_path(repo_root: &Path, skill_name: &str) -> PathBuf {
repo_root
.join(".claude")
fn skill_install_path(base: &Path, skill_name: &str) -> PathBuf {
base.join(".claude")
.join("skills")
.join(skill_name)
.join("SKILL.md")
}

fn user_home() -> Result<PathBuf> {
my_home()
.context("failed to determine home directory")?
.context("home directory not found")
}
Comment on lines +33 to +37

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

📝 Info: user_home() follows existing my_home() error-handling pattern

The new user_home() function at src/commands/skill.rs:33-37 uses the same double-.context() pattern as src/config/storage.rs:47-49 to handle the Result<Option<PathBuf>> return type of homedir::my_home(). This is consistent and correct — the first .context() handles IO errors and the second handles the None case (home directory not found).

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


fn git_root() -> Result<PathBuf> {
let output = Command::new("git")
.args(["rev-parse", "--show-toplevel"])
Expand All @@ -52,12 +58,12 @@ fn install_skill(repo_root: &Path, skill_name: &str, content: &str) -> Result<()
Ok(())
}

pub fn handle(command: Option<&SkillCommands>) -> Result<()> {
let root = git_root()?;
pub fn handle(command: Option<&SkillCommands>, user: bool) -> Result<()> {
let base = if user { user_home()? } else { git_root()? };
match command {
None => install_skill(&root, "detail-bugs", BUGS_SKILL_CONTENT),
None => install_skill(&base, "detail-bugs", BUGS_SKILL_CONTENT),
Some(SkillCommands::Rules) => {
install_skill(&root, "detail-create-rules", RULES_SKILL_CONTENT)
install_skill(&base, "detail-create-rules", RULES_SKILL_CONTENT)
}
}
}
Expand Down Expand Up @@ -101,4 +107,13 @@ mod tests {
PathBuf::from("/work/repo/.claude/skills/detail-create-rules/SKILL.md")
);
}

#[test]
fn skill_install_path_user_level() {
let path = skill_install_path(Path::new("/home/alice"), "detail-bugs");
assert_eq!(
path,
PathBuf::from("/home/alice/.claude/skills/detail-bugs/SKILL.md")
);
}
}
6 changes: 5 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ impl Cli {
Commands::SatisfyingSort => commands::satisfying_sort::handle().await,
Commands::Repos { command } => commands::repos::handle(command, &self).await,
Commands::Scans { command } => commands::scans::handle(command, &self).await,
Commands::Skill { command } => commands::skill::handle(command.as_ref()),
Commands::Skill { user, command } => commands::skill::handle(command.as_ref(), *user),
Commands::Update => commands::update::handle().await,
Commands::Version => {
console::Term::stdout().write_line(&format!("detail-cli v{VERSION}"))?;
Expand Down Expand Up @@ -209,6 +209,10 @@ enum Commands {

/// Install Detail skills (default: detail-bugs)
Skill {
/// Install to user-level ~/.claude/skills instead of the current repo
#[arg(long, global = true)]
user: bool,
Comment on lines +212 to +214

@devin-ai-integration devin-ai-integration Bot Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

📝 Info: global = true on --user propagates to subcommands but isn't shown in subcommand help

The #[arg(long, global = true)] at src/lib.rs:213 makes --user valid both before and after the rules subcommand (e.g. detail skill --user rules and detail skill rules --user). However, clap-markdown does not render global options in subcommand help sections, so docs/HELP.md:502-506 shows detail skill rules usage without [OPTIONS]. This is a clap-markdown limitation, not a code bug — the flag works correctly at runtime. Users may be confused that --user isn't documented under the rules subcommand, but discoverability via detail skill rules --help (which clap renders at runtime) should show it.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good call — added global = true so both detail skill --user rules and detail skill rules --user work. Fixed in 7c62d1d.


#[command(subcommand)]
command: Option<commands::skill::SkillCommands>,
},
Expand Down
Loading