diff --git a/USAGE.md b/USAGE.md index 873dde913d..5a95d4fad1 100644 --- a/USAGE.md +++ b/USAGE.md @@ -522,21 +522,21 @@ cd rust `SKILL.md` or a standalone markdown file. This is useful when a companion repository ships a skill prompt that should be available through `/skills`. -For example, install TweetClaw as an X/Twitter automation skill: +For example, install the portable X Twitter Scraper Skill: ```bash # From a parent directory that contains claw-code -git clone https://github.com/Xquik-dev/tweetclaw +git clone --depth 1 https://github.com/Xquik-dev/x-twitter-scraper cd claw-code/rust -./target/debug/claw skills install ../../tweetclaw/skills/tweetclaw -./target/debug/claw skills show tweetclaw -./target/debug/claw skills uninstall tweetclaw +./target/debug/claw skills install ../../x-twitter-scraper/skills/x-twitter-scraper +./target/debug/claw skills show x-twitter-scraper +./target/debug/claw skills uninstall x-twitter-scraper ``` -TweetClaw gives `claw` users a local skill guide for OpenClaw/Xquik workflows -such as tweet search, reply search, follower export, monitors, webhooks, and -approval-gated posting. Configure any Xquik credentials outside the prompt and -avoid pasting API keys into chat. +The Skill gives `claw` portable instructions for X research and Xquik API +workflows. Installing a Skill does not add a plugin or network transport. +Verify required tools separately. Configure credentials outside the prompt, +and never paste API keys into chat. ## Author a local agent diff --git a/rust/crates/commands/src/lib.rs b/rust/crates/commands/src/lib.rs index 7908691374..029fcbfd47 100644 --- a/rust/crates/commands/src/lib.rs +++ b/rust/crates/commands/src/lib.rs @@ -4240,6 +4240,9 @@ fn parse_skill_frontmatter(contents: &str) -> (Option, Option) { if trimmed == "---" { break; } + if line.trim_start() != line { + continue; + } if let Some(value) = trimmed.strip_prefix("name:") { let value = unquote_frontmatter_value(value.trim()); if !value.is_empty() { @@ -4297,6 +4300,9 @@ fn parse_agent_frontmatter( if trimmed == "---" { break; } + if line.trim_start() != line { + continue; + } if let Some(value) = trimmed.strip_prefix("name:") { let value = unquote_frontmatter_value(value.trim()); if !value.is_empty() { @@ -7029,6 +7035,18 @@ mod tests { assert_eq!(description.as_deref(), Some("Quoted description")); } + #[test] + fn frontmatter_parsers_ignore_nested_metadata() { + let contents = "---\nname: root-name\ndescription: Root description\nmetadata:\n name: nested-name\n description: Nested description\n---\n"; + let (skill_name, skill_description) = super::parse_skill_frontmatter(contents); + assert_eq!(skill_name.as_deref(), Some("root-name")); + assert_eq!(skill_description.as_deref(), Some("Root description")); + + let (agent_name, agent_description, _, _) = super::parse_agent_frontmatter(contents); + assert_eq!(agent_name.as_deref(), Some("root-name")); + assert_eq!(agent_description.as_deref(), Some("Root description")); + } + #[test] fn installs_skill_into_user_registry_and_preserves_nested_files() { let workspace = temp_dir("skills-install-workspace");