lean_ctx/tools/registered/
ctx_skillify.rs1use rmcp::ErrorData;
2use rmcp::model::Tool;
3use serde_json::{Map, Value, json};
4
5use crate::server::tool_trait::{McpTool, ToolContext, ToolOutput, get_str};
6use crate::tool_defs::tool_def;
7
8pub struct CtxSkillifyTool;
9
10impl McpTool for CtxSkillifyTool {
11 fn name(&self) -> &'static str {
12 "ctx_skillify"
13 }
14
15 fn tool_def(&self) -> Tool {
16 tool_def(
17 "ctx_skillify",
18 "WORKFLOW: mine to extract patterns → list to review → promote to activate.\n\
19 Codifies patterns into .cursor/rules/skillify-*.mdc.\n\
20 Actions: mine|list|status|promote. Idempotent.\n\
21 ANTIPATTERN: one-off rules → write .mdc by hand.",
22 json!({
23 "type": "object",
24 "properties": {
25 "action": {
26 "type": "string",
27 "enum": ["mine", "list", "status", "promote"],
28 "description": "mine|list|status|promote"
29 },
30 "slug": {
31 "type": "string",
32 "description": "Rule slug (for promote)"
33 }
34 },
35 "allOf": [
36 {
37 "if": { "properties": { "action": { "const": "promote" } }, "required": ["action"] },
38 "then": { "required": ["action", "slug"] }
39 }
40 ]
41 }),
42 )
43 }
44
45 fn handle(
46 &self,
47 args: &Map<String, Value>,
48 ctx: &ToolContext,
49 ) -> Result<ToolOutput, ErrorData> {
50 let action = get_str(args, "action").unwrap_or_else(|| "mine".to_string());
51 let slug = get_str(args, "slug");
52 let result =
53 crate::tools::ctx_skillify::handle(&ctx.project_root, &action, slug.as_deref());
54 Ok(ToolOutput::simple(result))
55 }
56}