[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M71T59R9QSB2D92GGTXYMMFT":3,"skill-same:01M71T59R9QSB2D92GGTXYMMFT":68},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":20,"frontMatter":21,"refName":22,"commitSha":23,"skillDirectory":24,"forksCount":13,"repositoryHtmlUrl":25,"repositoryHomepageUrl":6,"ownerHtmlUrl":26,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":27,"install":28,"resources":41},"01M71T59R9QSB2D92GGTXYMMFT","modules",null,"fxcl\u002Fopencode-rs","fxcl","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F74125308?v=4","01M71T4Q1Y6VFEC8ZSS2DWCC7K","okk","01M71T4Q2RFFVTSJZZNS2ZV2DR",0,"MIT","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fskill.md",[],[5],"2026-11-10 13:02:02",false,"# PRD: skill Module\n\n## Module Overview\n\n- **Module Name**: `skill`\n- **Source Path**: `packages\u002Fopencode\u002Fsrc\u002Fskill\u002F`\n- **Type**: Integration Service\n- **Rust Crate**: `crates\u002Fskill\u002F`\n- **Purpose**: Discovers, loads, and manages agent skills — markdown files (`SKILL.md`) that inject additional instructions into the agent's context. Supports local filesystem discovery, URL-based remote skill packs, and permission-based filtering.\n\n---\n\n## Functionality\n\n### Core Features\n\n1. **Skill Discovery** — Scans multiple directories for `SKILL.md` files using glob patterns\n2. **Multi-Source Loading** — Global `~\u002F.claude\u002Fskills\u002F`, `~\u002F.agents\u002Fskills\u002F`, project-level dirs, config-defined paths, URL-based remote packs\n3. **Frontmatter Parsing** — Extracts `name` and `description` from YAML frontmatter; `content` is the markdown body\n4. **Remote Skill Packs** — Downloads skill packs from URLs via `index.json` manifest\n5. **Deduplication Warning** — Warns on duplicate skill names (last write wins)\n6. **Permission Filtering** — `available(agent?)` filters skills by agent permission rules\n7. **Skill Formatting** — Formats skill list for injection into agent prompts (verbose XML or compact markdown)\n8. **Feature Flag** — `OPENCODE_DISABLE_EXTERNAL_SKILLS` disables global\u002Fproject external skill scanning\n\n---\n\n## SKILL.md Format\n\n```markdown\n---\nname: my-skill\ndescription: A brief description of what this skill does.\n---\n\n# Skill Content\n\nMarkdown instructions injected into the agent context...\n```\n\n### Frontmatter Schema\n\n```rust\n#[derive(Debug, Deserialize, Serialize)]\nstruct SkillFrontmatter {\n    name: String,\n    description: String,\n}\n```\n\n---\n\n## API Surface\n\n### Types\n\n```rust\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct SkillInfo {\n    pub name: String,\n    pub description: String,\n    \u002F\u002F\u002F Absolute file path to the SKILL.md\n    pub location: PathBuf,\n    \u002F\u002F\u002F Markdown body (without frontmatter)\n    pub content: String,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct RemoteSkillManifest {\n    pub skills: Vec\u003CRemoteSkillEntry>,\n}\n\n#[derive(Debug, Clone, Serialize, Deserialize)]\npub struct RemoteSkillEntry {\n    pub name: String,\n    pub files: Vec\u003CString>,\n}\n```\n\n### Service Interface\n\n```rust\npub struct SkillService {\n    skills: Arc\u003CRwLock\u003CHashMap\u003CString, SkillInfo>>>,\n    dirs: Arc\u003CRwLock\u003CHashSet\u003CPathBuf>>>,\n    config: Arc\u003CConfigService>,\n    permission: Arc\u003CPermissionService>,\n    cache_dir: PathBuf,\n    http: reqwest::Client,\n}\n\nimpl SkillService {\n    \u002F\u002F\u002F Discover and load all skills from all configured sources\n    pub async fn discover_and_load(&self, ctx: &InstanceContext) -> Result\u003C(), SkillError> {\n        let paths = self.scan_all_sources(ctx).await?;\n        for path in paths {\n            if let Err(e) = self.load_skill(&path).await {\n                tracing::warn!(path = %path.display(), error = %e, \"Failed to load skill\");\n                \u002F\u002F Per AC: publish error on bus, don't fail the whole load\n                let _ = self.bus.publish(\"session.error\", json!({\n                    \"type\": \"skill_parse_error\",\n                    \"path\": path.to_string_lossy(),\n                    \"error\": e.to_string(),\n                })).await;\n            }\n        }\n        Ok(())\n    }\n\n    \u002F\u002F\u002F Get a skill by name\n    pub async fn get(&self, name: &str) -> Option\u003CSkillInfo> {\n        self.skills.read().await.get(name).cloned()\n    }\n\n    \u002F\u002F\u002F Get all skills (optionally filtered by agent permissions)\n    pub async fn all(&self, agent: Option\u003C&AgentInfo>) -> Vec\u003CSkillInfo> {\n        let skills: Vec\u003C_> = self.skills.read().await.values().cloned().collect();\n        if let Some(agent_info) = agent {\n            skills.into_iter()\n                .filter(|s| self.permission.is_allowed(agent_info, \"skill\", &s.name))\n                .collect()\n        } else {\n            skills\n        }\n    }\n\n    \u002F\u002F\u002F Get all directories containing skills\n    pub async fn dirs(&self) -> Vec\u003CPathBuf> {\n        self.dirs.read().await.iter().cloned().collect()\n    }\n\n    \u002F\u002F\u002F Format skills for injection into agent context\n    pub fn fmt(&self, skills: &[SkillInfo], verbose: bool) -> String {\n        if verbose {\n            skills.iter().map(|s| {\n                format!(\n                    \"\u003Cskill>\\n  \u003Cname>{}\u003C\u002Fname>\\n  \u003Cdescription>{}\u003C\u002Fdescription>\\n  \u003Clocation>{}\u003C\u002Flocation>\\n\u003C\u002Fskill>\",\n                    s.name, s.description, s.location.display()\n                )\n            }).collect::\u003CVec\u003C_>>().join(\"\\n\")\n        } else {\n            skills.iter().map(|s| {\n                format!(\"- **{}**: {}\", s.name, s.description)\n            }).collect::\u003CVec\u003C_>>().join(\"\\n\")\n        }\n    }\n\n    \u002F\u002F\u002F Pull skills from a remote URL\n    pub async fn pull(&self, url: &str) -> Result\u003CVec\u003CPathBuf>, SkillError> {\n        \u002F\u002F 1. Fetch \u003Curl>\u002Findex.json\n        let manifest: RemoteSkillManifest = self.http\n            .get(format!(\"{}\u002Findex.json\", url))\n            .send().await?\n            .json().await?;\n\n        let cache_dir = self.cache_dir.join(url_to_dir_name(url));\n        tokio::fs::create_dir_all(&cache_dir).await?;\n\n        \u002F\u002F 2. Download each file\n        for entry in &manifest.skills {\n            for file in &entry.files {\n                let content = self.http\n                    .get(format!(\"{}\u002F{}\", url, file))\n                    .send().await?\n                    .text().await?;\n                let dest = cache_dir.join(&entry.name).join(file);\n                tokio::fs::create_dir_all(dest.parent().unwrap()).await?;\n                tokio::fs::write(&dest, content).await?;\n            }\n        }\n\n        \u002F\u002F 3. Return paths containing SKILL.md\n        let paths = glob(&cache_dir, \"**\u002FSKILL.md\")?;\n        for path in &paths {\n            let _ = self.load_skill(path).await;\n        }\n        Ok(paths)\n    }\n}\n```\n\n### `SkillError`\n\n```rust\n#[derive(Debug, Error)]\npub enum SkillError {\n    #[error(\"Skill file not found: {0}\")]\n    NotFound(String),\n\n    #[error(\"Failed to read skill file: {0}\")]\n    ReadError(#[source] std::io::Error),\n\n    #[error(\"Failed to parse frontmatter: {0}\")]\n    ParseError(String),\n\n    #[error(\"Missing frontmatter field '{field}' in {path}\")]\n    MissingField { field: String, path: PathBuf },\n\n    #[error(\"Duplicate skill name: {0}\")]\n    DuplicateName(String),\n\n    #[error(\"HTTP error: {0}\")]\n    Http(#[from] reqwest::Error),\n\n    #[error(\"Invalid URL: {0}\")]\n    InvalidUrl(String),\n\n    #[error(\"Remote fetch failed: {0}\")]\n    RemoteError(String),\n}\n```\n\n---\n\n## Discovery Algorithm\n\n```rust\nimpl SkillService {\n    async fn scan_all_sources(&self, ctx: &InstanceContext) -> Result\u003CVec\u003CPathBuf>, SkillError> {\n        let mut matches = Vec::new();\n        let mut dirs = HashSet::new();\n\n        \u002F\u002F Feature flag check\n        if std::env::var(\"OPENCODE_DISABLE_EXTERNAL_SKILLS\").is_ok() {\n            \u002F\u002F Only load project-local skills\n            let project_skills = self.scan_dir(&ctx.project_dir().join(\".claude\u002Fskills\")).await?;\n            matches.extend(project_skills);\n        } else {\n            \u002F\u002F Global sources\n            let home = dirs::home_dir().unwrap_or_default();\n            for glob_pattern in [\n                home.join(\".claude\u002Fskills\u002F**\u002FSKILL.md\"),\n                home.join(\".agents\u002Fskills\u002F**\u002FSKILL.md\"),\n            ] {\n                matches.extend(glob_path(&glob_pattern).await?);\n                if let Some(parent) = glob_pattern.parent() {\n                    dirs.insert(parent.to_path_buf());\n                }\n            }\n\n            \u002F\u002F Project-local sources (walk up from project dir)\n            let project_root = &ctx.project_dir();\n            for subdir in [\".claude\u002Fskills\", \".agents\u002Fskills\"] {\n                let path = project_root.join(subdir);\n                if path.exists() {\n                    matches.extend(glob_path(&path.join(\"**\u002FSKILL.md\")).await?);\n                    dirs.insert(path);\n                }\n            }\n\n            \u002F\u002F Config-defined custom paths\n            for custom_path in self.config.skills().paths() {\n                matches.extend(glob_path(&custom_path.join(\"**\u002FSKILL.md\")).await?);\n                dirs.insert(custom_path);\n            }\n        }\n\n        \u002F\u002F Remote URLs\n        for url in self.config.skills().urls() {\n            if let Err(e) = self.pull(url).await {\n                tracing::warn!(url, error = %e, \"Failed to pull remote skills\");\n            }\n        }\n\n        \u002F\u002F Update dirs cache\n        *self.dirs.write().await = dirs;\n\n        Ok(matches)\n    }\n\n    async fn load_skill(&self, path: &Path) -> Result\u003CSkillInfo, SkillError> {\n        let content = tokio::fs::read_to_string(path).await\n            .map_err(SkillError::ReadError)?;\n\n        let (frontmatter, body) = split_frontmatter(&content)?;\n        let meta: SkillFrontmatter = serde_yaml::from_str(&frontmatter)\n            .map_err(|e| SkillError::ParseError(e.to_string()))?;\n\n        let info = SkillInfo {\n            name: meta.name,\n            description: meta.description,\n            location: path.to_path_buf(),\n            content: body.to_string(),\n        };\n\n        \u002F\u002F Check for duplicate\n        let mut skills = self.skills.write().await;\n        if skills.contains_key(&info.name) {\n            tracing::warn!(name = %info.name, \"Duplicate skill name (overwriting)\");\n        }\n        skills.insert(info.name.clone(), info.clone());\n\n        Ok(info)\n    }\n}\n\nfn split_frontmatter(content: &str) -> Result\u003C(String, &str), SkillError> {\n    if let Some(rest) = content.strip_prefix(\"---\\n\") {\n        if let Some(end) = rest.find(\"\\n---\\n\") {\n            return Ok((rest[..end].to_string(), &rest[end + 5..]));\n        }\n    }\n    Err(SkillError::ParseError(\"Missing --- frontmatter delimiters\".into()))\n}\n```\n\n---\n\n## Crate Layout\n\n```\ncrates\u002Fskill\u002F\n├── Cargo.toml       # glob = \"0.3\", reqwest = { version = \"0.11\", features = [\"json\"] }, serde_yaml = \"0.9\"\n├── src\u002F\n│   ├── lib.rs       # SkillService, SkillInfo, SkillError\n│   ├── discovery.rs # Scan and load from filesystem\n│   ├── remote.rs    # Remote skill pack pulling\n│   ├── format.rs    # Formatting for agent context\n│   └── permissions.rs # Permission filtering\n└── tests\u002F\n    └── skill_tests.rs\n```\n\n### `Cargo.toml`\n\n```toml\n[package]\nname = \"opencode-skill\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\ntokio = { version = \"1.45\", features = [\"fs\", \"sync\", \"rt\"] }\nglob = \"0.3\"\nreqwest = { version = \"0.12\", features = [\"json\", \"rustls-tls\"] }\nserde = { version = \"1.0\", features = [\"derive\"] }\nserde_yaml = \"0.9\"\nserde_json = \"1.0\"\nthiserror = \"2.0\"\ntracing = \"0.1\"\nwalkdir = \"2\"\nanyhow = \"1.0\"\ndirs = \"5\"\n\n[dev-dependencies]\ntempfile = \"3\"\ntokio-test = \"0.4\"\nwiremock = \"0.6\"\n```\n\n---\n\n## Dependencies\n\n| Dependency | Purpose |\n|---|---|\n| `config` module | `config.directories()`, `config.skills.paths`, `config.skills.urls` |\n| `bus` module | Error event publishing on skill parse failure |\n| `permission` module | `Permission.is_allowed(\"skill\", name, agent)` |\n| `global` module | `Global.Path.home`, `Global.Path.cache` |\n| `reqwest` | Downloading remote skill packs |\n| `glob` \u002F `walkdir` | Pattern-based file scanning |\n| `serde_yaml` | Frontmatter parsing |\n| `dirs` | Home directory detection |\n\n---\n\n## Acceptance Criteria\n\n- [x] Skills are discovered from all configured source directories\n- [x] Frontmatter `name` and `description` are extracted correctly\n- [x] Duplicate skill names log a warning (last wins)\n- [x] `get(name)` returns the correct skill info\n- [x] `available(agent)` filters skills denied by agent permission rules\n- [x] Remote skill packs are downloaded and cached\n- [x] `OPENCODE_DISABLE_EXTERNAL_SKILLS` prevents global\u002Fproject discovery\n- [x] `fmt()` produces correct verbose XML and compact markdown output\n- [x] Parse errors publish `session.error` on the bus\n\n---\n\n## Test Design\n\n### Unit Tests\n\n```rust\n#[test]\nfn test_split_frontmatter_extracts_correctly() {\n    let content = \"---\\nname: my-skill\\ndescription: Does something.\\n---\\n\\n# Content\\nHello\";\n    let (fm, body) = split_frontmatter(content).unwrap();\n    let meta: SkillFrontmatter = serde_yaml::from_str(&fm).unwrap();\n    assert_eq!(meta.name, \"my-skill\");\n    assert_eq!(meta.description, \"Does something.\");\n    assert_eq!(body.trim(), \"# Content\\nHello\");\n}\n\n#[test]\nfn test_split_frontmatter_missing_delimiter_errors() {\n    let content = \"no frontmatter\\n---\\nname: x\\n---\\n\";\n    assert!(split_frontmatter(content).is_err());\n}\n\n#[test]\nfn test_split_frontmatter_empty_frontmatter() {\n    let content = \"---\\n---\\nbody content\";\n    let (fm, body) = split_frontmatter(content).unwrap();\n    assert!(fm.is_empty());\n    assert_eq!(body.trim(), \"body content\");\n}\n\n#[tokio::test]\nasync fn test_load_skill_extracts_frontmatter() {\n    let tmp = TempDir::new().unwrap();\n    let path = tmp.path().join(\"SKILL.md\");\n    tokio::fs::write(&path, \"---\\nname: test\\ndescription: desc\\n---\\n\\n# Test\").await.unwrap();\n\n    let svc = SkillService::new_test().await;\n    let info = svc.load_skill(&path).await.unwrap();\n    assert_eq!(info.name, \"test\");\n    assert_eq!(info.description, \"desc\");\n}\n\n#[tokio::test]\nasync fn test_get_returns_skill_by_name() {\n    let svc = SkillService::new_test().await;\n    let tmp = TempDir::new().unwrap();\n    let path = tmp.path().join(\"SKILL.md\");\n    tokio::fs::write(&path, \"---\\nname: my-skill\\ndescription: desc\\n---\\n\\n# Body\").await.unwrap();\n    svc.load_skill(&path).await.unwrap();\n\n    let info = svc.get(\"my-skill\").await;\n    assert!(info.is_some());\n    assert_eq!(info.unwrap().description, \"desc\");\n}\n\n#[test]\nfn test_fmt_verbose_produces_xml() {\n    let svc = SkillService::new_test().await;\n    let skills = vec![SkillInfo {\n        name: \"s1\".into(),\n        description: \"d1\".into(),\n        location: PathBuf::from(\"\u002Fpath\u002FSKILL.md\"),\n        content: \"# s1\".into(),\n    }];\n    let out = svc.fmt(&skills, true);\n    assert!(out.contains(\"\u003Cskill>\"));\n    assert!(out.contains(\"\u003Cname>s1\u003C\u002Fname>\"));\n    assert!(out.contains(\"\u003Cdescription>d1\u003C\u002Fdescription>\"));\n}\n\n#[test]\nfn test_fmt_compact_produces_markdown() {\n    let svc = SkillService::new_test().await;\n    let skills = vec![SkillInfo {\n        name: \"s1\".into(),\n        description: \"d1\".into(),\n        location: PathBuf::from(\"\u002Fpath\u002FSKILL.md\"),\n        content: \"# s1\".into(),\n    }];\n    let out = svc.fmt(&skills, false);\n    assert!(out.contains(\"- **s1**: d1\"));\n    assert!(!out.contains(\"\u003Cskill>\"));\n}\n\n#[tokio::test]\nasync fn test_duplicate_name_warns() {\n    let svc = SkillService::new_test().await;\n    let tmp = TempDir::new().unwrap();\n\n    \u002F\u002F Two files with same name\n    tokio::fs::write(tmp.path().join(\"a\u002FSKILL.md\"), \"---\\nname: dup\\ndescription: first\\n---\\n# A\").await.unwrap();\n    tokio::fs::write(tmp.path().join(\"b\u002FSKILL.md\"), \"---\\nname: dup\\ndescription: second\\n---\\n# B\").await.unwrap();\n\n    svc.load_skill(&tmp.path().join(\"a\u002FSKILL.md\")).await.unwrap();\n    \u002F\u002F Second load should warn but not panic\n    svc.load_skill(&tmp.path().join(\"b\u002FSKILL.md\")).await.unwrap();\n\n    \u002F\u002F Last one wins\n    let info = svc.get(\"dup\").await.unwrap();\n    assert_eq!(info.description, \"second\");\n}\n```\n\n### Integration Tests\n\n```rust\n#[tokio::test]\nasync fn test_pull_remote_skill_pack() {\n    \u002F\u002F Mock HTTP server serving index.json + SKILL.md files\n    Mock::given(get, \"\u002Findex.json\")\n        .respond_with(json_response(200, &RemoteSkillManifest {\n            skills: vec![RemoteSkillEntry {\n                name: \"remote-skill\".into(),\n                files: vec![\"SKILL.md\".into()],\n            }],\n        }))\n        .and(\n            Mock::given(get, \"\u002FSKILL.md\")\n                .respond_with(body(\"---\\nname: remote-skill\\ndescription: From remote\\n---\\n\\n# Remote\"))\n        )\n        .mount(&mock_server)\n        .await;\n\n    let svc = SkillService::new_test().await;\n    svc.pull(&mock_server.uri()).await.unwrap();\n\n    let info = svc.get(\"remote-skill\").await;\n    assert!(info.is_some());\n}\n```\n\n---\n\n## Source Reference\n\n*Source: `packages\u002Fopencode\u002Fsrc\u002Fskill\u002Findex.ts`*\n*No existing Rust equivalent — implement in `crates\u002Fskill\u002F`*\n",{},"main","e8d0b9937ed05c662835f4a456a9b722b145e86d","docs\u002FPRD\u002F20_INTEGRATION\u002Fmodules","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs","https:\u002F\u002Fgithub.com\u002Ffxcl","2026-05-01 15:45:35",{"source":7,"skillName":5,"commands":29,"prompt":39,"zipAvailable":40},[30,33,36],{"tool":31,"command":32},"npx","npx skills add fxcl\u002Fopencode-rs --skill modules",{"tool":34,"command":35},"bunx","bunx skills add fxcl\u002Fopencode-rs --skill modules",{"tool":37,"command":38},"pnpm","pnpm dlx skills add fxcl\u002Fopencode-rs --skill modules","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fskill.md",true,[42,48,52,56,60,64],{"path":43,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":46,"sourceHtmlUrl":47},"acp.md","REFERENCE","参考文档",10895,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Facp.md",{"path":49,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":50,"sourceHtmlUrl":51},"control-plane.md",8325,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fcontrol-plane.md",{"path":53,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":54,"sourceHtmlUrl":55},"lsp.md",12591,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Flsp.md",{"path":57,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":58,"sourceHtmlUrl":59},"mcp.md",10101,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fmcp.md",{"path":61,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":62,"sourceHtmlUrl":63},"plugin.md",13793,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fplugin.md",{"path":65,"resourceType":44,"resourceTypeDesc":45,"sizeBytes":66,"sourceHtmlUrl":67},"provider.md",27696,"https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fdocs\u002FPRD\u002F20_INTEGRATION\u002Fmodules\u002Fprovider.md",[69,90,102,114,125,141],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":80,"publishedAt":18},"01M71T5NE7XB5P94GAMM3HR0HA","test-writer","Write focused tests with strong coverage and TDD discipline","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Ftest-writer\u002FSKILL.md",[75],{"categoryNo":76,"categoryName":77,"taxonomyType":78,"taxonomyTypeDesc":79},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",[81,82,83,84,85,86,87,88,89],"writer","test writer","test","coverage","with","tests","discipline","tdd","write",{"skillNo":91,"name":92,"nameZh":6,"description":93,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":96,"publishedAt":18},"01M71T5MF6FXF62J5AH9WPEDXC","security-auditor","Assess security posture and identify exploitable risks","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Fsecurity-auditor\u002FSKILL.md",[],[97,98,99,100,101],"security auditor","auditor","security","assess","security posture",{"skillNo":103,"name":104,"nameZh":6,"description":105,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":108,"publishedAt":18},"01M71T5JG3W7G9E6P29CAVQNE4","refactorer","Improve code structure without changing behavior","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Frefactorer\u002FSKILL.md",[],[104,109,110,111,112,113],"structure","behavior","code","code structure","improve",{"skillNo":115,"name":116,"nameZh":6,"description":117,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":118,"categories":119,"keywords":120,"publishedAt":18},"01M71T5H8K9AV8APGA9JWEBCYR","performance","Optimize runtime, memory, and throughput bottlenecks","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Fperformance\u002FSKILL.md",[],[116,121,122,123,124],"runtime","optimize","memory","throughput",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":18},"01M71T5G4WG6YKHXNJ0TJSS35K","doc-writer","Produce clear technical documentation and developer guides","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Fdoc-writer\u002FSKILL.md",[],[81,132,133,134,135,136,137,138,139,140],"doc writer","doc","clear","documentation","produce","technical","developer","technical documentation","guides",{"skillNo":142,"name":143,"nameZh":6,"description":144,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":145,"categories":146,"keywords":147,"publishedAt":18},"01M71T5F3RKC41MTMKGNXB4SH9","devops","Improve CI\u002FCD, deployment, and operational reliability","https:\u002F\u002Fgithub.com\u002Ffxcl\u002Fopencode-rs\u002Fblob\u002Fmain\u002Fopencode-rust\u002Fcrates\u002Fcore\u002Fskills\u002Fdevops\u002FSKILL.md",[],[143,113,148,149,150,151,152,153],"reliability","operational","cd","deployment","CI\u002FCD","ci"]