Skip to main content

conclavelib/
skill.rs

1//! The packaged Claude Code skill — the CLI is the single source of truth (DESIGN.md §13).
2//!
3//! `conclave skill` emits a complete `SKILL.md`: a curated guide (the mental model, the two
4//! surfaces, one-time install, examples) followed by an auto-generated command reference so the
5//! flag list never drifts from the actual CLI. `conclave skill install` writes it under the Claude
6//! Code skills directory so `/conclave` becomes available. The binary generates the reference (clap
7//! lives in the binary) and passes it to [`render`]; this module owns the curated body and paths.
8
9use std::path::{Path, PathBuf};
10
11/// The curated skill body (frontmatter + prose). The command reference is appended by [`render`].
12const SKILL_BODY: &str = include_str!("skill/SKILL.md");
13
14/// Renders the full `SKILL.md`: the curated guide plus the generated command reference.
15#[must_use]
16pub fn render(command_reference: &str) -> String {
17    format!(
18        "{}\n\n## Command reference\n\nAuto-generated from `conclave --help` — the authoritative, always-current flag list for every verb.\n\n{}\n",
19        SKILL_BODY.trim_end(),
20        command_reference.trim_end(),
21    )
22}
23
24/// The install path for the skill under `skills_dir` (`<skills_dir>/conclave/SKILL.md`).
25#[must_use]
26pub fn install_path(skills_dir: &Path) -> PathBuf {
27    skills_dir.join("conclave").join("SKILL.md")
28}
29
30#[cfg(test)]
31mod tests {
32    // Tests relax `unwrap_used` (house convention; DESIGN.md §22).
33    #![allow(clippy::unwrap_used)]
34
35    use super::*;
36    use pretty_assertions::assert_eq;
37
38    #[test]
39    fn skill_render_has_frontmatter_and_appends_the_reference() {
40        let rendered = render("### conclave register\n```\n--username ...\n```");
41        // Valid skill frontmatter at the very top.
42        assert!(rendered.starts_with("---\n"), "skill must start with YAML frontmatter: {}", &rendered[..40]);
43        assert!(rendered.contains("name: conclave"));
44        // The join section (the headline action) and the generated reference are both present.
45        assert!(rendered.contains("join_channel"), "skill must document joining via the bridge tool");
46        assert!(rendered.contains("## Command reference"));
47        assert!(rendered.contains("conclave register"));
48    }
49
50    #[test]
51    fn skill_install_path_targets_the_conclave_skill_dir() {
52        assert_eq!(install_path(Path::new("/home/x/.claude/skills")), Path::new("/home/x/.claude/skills/conclave/SKILL.md"));
53    }
54}