This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kit.git

commit 8fe5fbe74ceae9131abdd95fa9bfbafaef251213
Author: Jinal Sarvaiya <[email protected]>
AuthorDate: Tue Oct 20 14:24:25 2026 +0100

    fix #243: make camel-kit skills discoverable and correctly scoped in Claude 
Code
---
 .../camelkit/generator/SkillResourceInstaller.java | 10 +++-
 .../src/main/resources/agents/registry/claude.yaml |  2 +-
 .../resources/skills/camel-brainstorm/SKILL.md     |  2 +-
 .../src/main/resources/skills/camel-debug/SKILL.md |  2 +-
 .../main/resources/skills/camel-execute/SKILL.md   |  2 +-
 .../main/resources/skills/camel-knowledge/SKILL.md |  2 +-
 .../main/resources/skills/camel-migrate/SKILL.md   |  2 +-
 .../src/main/resources/skills/camel-plan/SKILL.md  |  2 +-
 .../src/main/resources/skills/camel-ship/SKILL.md  |  2 +-
 .../src/main/resources/skills/camel-start/SKILL.md |  2 +-
 .../main/resources/skills/camel-validate/SKILL.md  |  2 +-
 .../main/resources/templates/claude/camel-ship.md  |  2 +-
 .../camelkit/config/AgentRegistryTest.java         |  2 +-
 .../camelkit/generator/ClaudeGeneratorTest.java    | 60 ++++++++++++++++++++--
 .../generator/ShippedAssetStructureTest.java       |  3 +-
 15 files changed, 78 insertions(+), 19 deletions(-)

diff --git 
a/camel-kit-core/src/main/java/io/github/luigidemasi/camelkit/generator/SkillResourceInstaller.java
 
b/camel-kit-core/src/main/java/io/github/luigidemasi/camelkit/generator/SkillResourceInstaller.java
index 44fe579c..3832a8e1 100644
--- 
a/camel-kit-core/src/main/java/io/github/luigidemasi/camelkit/generator/SkillResourceInstaller.java
+++ 
b/camel-kit-core/src/main/java/io/github/luigidemasi/camelkit/generator/SkillResourceInstaller.java
@@ -156,7 +156,8 @@ class SkillResourceInstaller {
                 }
             }
             if 
(AgentGeneratorStrategy.BOB2.descriptorValue().equals(ctx.agentName())
-                    || 
AgentGeneratorStrategy.QWEN.descriptorValue().equals(ctx.agentName())) {
+                    || 
AgentGeneratorStrategy.QWEN.descriptorValue().equals(ctx.agentName())
+                    || 
AgentGeneratorStrategy.CLAUDE.descriptorValue().equals(ctx.agentName())) {
                 // Bob Shell's native skill picker hides false values; 
same-name command stubs cannot override them.
                 boolean exposeCommand = 
AgentGeneratorStrategy.BOB2.descriptorValue().equals(ctx.agentName())
                         && workflow.commands().stream().anyMatch(command -> 
command.userFacing()
@@ -166,6 +167,9 @@ class SkillResourceInstaller {
             if 
(AgentGeneratorStrategy.COPILOT.descriptorValue().equals(ctx.agentName())) {
                 addCopilotReadableInternalSkillMetadata(destination);
             }
+            if 
(AgentGeneratorStrategy.CLAUDE.descriptorValue().equals(ctx.agentName())) {
+                addClaudeReadableInternalSkillMetadata(destination);
+            }
             if 
(AgentGeneratorStrategy.PI.descriptorValue().equals(ctx.agentName())) {
                 addPiReadableInternalSkillMetadata(destination);
             }
@@ -238,6 +242,10 @@ class SkillResourceInstaller {
         }
     }
 
+    void addClaudeReadableInternalSkillMetadata(Path skillFile) throws 
Exception {
+        addInternalSkillInvocationMetadata(skillFile, "Claude");
+    }
+
     void addCopilotReadableInternalSkillMetadata(Path skillFile) throws 
Exception {
         addInternalSkillInvocationMetadata(skillFile, "Copilot");
     }
diff --git a/camel-kit-core/src/main/resources/agents/registry/claude.yaml 
b/camel-kit-core/src/main/resources/agents/registry/claude.yaml
index 1795c7bc..bbb67314 100644
--- a/camel-kit-core/src/main/resources/agents/registry/claude.yaml
+++ b/camel-kit-core/src/main/resources/agents/registry/claude.yaml
@@ -2,7 +2,7 @@ id: claude
 displayName: Claude Code
 commandDirectory: .claude/commands
 skillsDirectory: .claude/skills
-generatesCommandStubs: true
+generatesCommandStubs: false
 commandFileFormat: md
 argumentPlaceholder: $ARGUMENTS
 mcpConfigPath: .mcp.json
diff --git a/camel-kit-core/src/main/resources/skills/camel-brainstorm/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-brainstorm/SKILL.md
index e95c14c6..c1699482 100644
--- a/camel-kit-core/src/main/resources/skills/camel-brainstorm/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-brainstorm/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-brainstorm
-description: Design and plan Camel integrations through collaborative dialogue.
+description: Use when designing a new Camel integration through collaborative 
dialogue to produce a design spec.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-debug/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-debug/SKILL.md
index 9b5a8e45..fe82e3ce 100644
--- a/camel-kit-core/src/main/resources/skills/camel-debug/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-debug/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-debug
-description: Ad-hoc troubleshooting for broken Camel routes outside of a 
pipeline run.
+description: Use when a Camel route is broken and needs ad-hoc troubleshooting 
outside of a pipeline run.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-execute/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-execute/SKILL.md
index 97d1c696..78164782 100644
--- a/camel-kit-core/src/main/resources/skills/camel-execute/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-execute/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-execute
-description: Execute a ready implementation plan derived from an approved 
design with an adversarial pre-filter and ordered spec and quality review.
+description: Use when executing a ready implementation plan with adversarial 
pre-filter and ordered spec and quality review.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-knowledge/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-knowledge/SKILL.md
index 373e8e43..f3265974 100644
--- a/camel-kit-core/src/main/resources/skills/camel-knowledge/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-knowledge/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-knowledge
-description: Look up Camel documentation, components, CVEs/security 
advisories, and versions.
+description: Use when looking up Apache Camel documentation, components, 
CVEs/security advisories, or version information.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-migrate/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-migrate/SKILL.md
index 96b2f6e7..f1d00b73 100644
--- a/camel-kit-core/src/main/resources/skills/camel-migrate/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-migrate/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-migrate
-description: Migrate an existing integration from another product to Apache 
Camel
+description: Use when migrating an existing integration from MuleSoft, 
BizTalk, Fuse, or older Camel to Apache Camel.
 user_invocable: false
 metadata:
   version: "2.0.0"
diff --git a/camel-kit-core/src/main/resources/skills/camel-plan/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-plan/SKILL.md
index cb2ea08d..bf6ebc2d 100644
--- a/camel-kit-core/src/main/resources/skills/camel-plan/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-plan/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-plan
-description: Break a design spec into implementation tasks with wave analysis.
+description: Use when an approved design spec needs to be broken into 
implementation tasks with wave analysis.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-ship/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-ship/SKILL.md
index 85b35cec..723a2ef2 100644
--- a/camel-kit-core/src/main/resources/skills/camel-ship/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-ship/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-ship
-description: Delegate the Technology Preview Ship workflow to the registered 
Camel-Kit CLI command.
+description: Use when the user explicitly asks to ship or publish a Camel 
project via the Technology Preview Ship workflow.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-start/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-start/SKILL.md
index 58797f8e..6ec7cc96 100644
--- a/camel-kit-core/src/main/resources/skills/camel-start/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-start/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-start
-description: Route to the right camel-kit skill for integration work.
+description: Use when the user wants to start an integration task and you need 
to pick the right camel-kit skill.
 user_invocable: true
 ---
 
diff --git a/camel-kit-core/src/main/resources/skills/camel-validate/SKILL.md 
b/camel-kit-core/src/main/resources/skills/camel-validate/SKILL.md
index 5a35f727..805d530a 100644
--- a/camel-kit-core/src/main/resources/skills/camel-validate/SKILL.md
+++ b/camel-kit-core/src/main/resources/skills/camel-validate/SKILL.md
@@ -1,6 +1,6 @@
 ---
 name: camel-validate
-description: Static quality analysis of Camel routes — correctness, security, 
anti-patterns.
+description: Use when running static quality analysis on Camel routes for 
correctness, security, and anti-patterns.
 user_invocable: false
 ---
 
diff --git a/camel-kit-core/src/main/resources/templates/claude/camel-ship.md 
b/camel-kit-core/src/main/resources/templates/claude/camel-ship.md
index fe3b14bb..0c9bbc23 100644
--- a/camel-kit-core/src/main/resources/templates/claude/camel-ship.md
+++ b/camel-kit-core/src/main/resources/templates/claude/camel-ship.md
@@ -1,6 +1,6 @@
 ---
 name: camel-ship
-description: Run the Camel Ship Technology Preview through Claude Code native 
subagents when the active session permits it.
+description: Use when the user explicitly asks to ship or publish a Camel 
project via the Technology Preview Ship workflow.
 argument-hint: "[ship-options]"
 user-invocable: true
 ---
diff --git 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/config/AgentRegistryTest.java
 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/config/AgentRegistryTest.java
index db3f1b5d..e1e49c77 100644
--- 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/config/AgentRegistryTest.java
+++ 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/config/AgentRegistryTest.java
@@ -29,7 +29,7 @@ class AgentRegistryTest {
         AgentConfig claude = AgentRegistry.get("claude");
         assertNotNull(claude);
         assertEquals("Claude Code", claude.name());
-        assertEquals(".claude/commands", claude.folder());
+        assertEquals(".claude/skills", claude.folder());
         assertEquals("md", claude.fileFormat());
         assertEquals("$ARGUMENTS", claude.argPlaceholder());
         assertEquals(".mcp.json", claude.mcpConfigPath());
diff --git 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ClaudeGeneratorTest.java
 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ClaudeGeneratorTest.java
index 5009a10e..054e4506 100644
--- 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ClaudeGeneratorTest.java
+++ 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ClaudeGeneratorTest.java
@@ -2,6 +2,7 @@ package io.github.luigidemasi.camelkit.generator;
 
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Set;
 
 import io.github.luigidemasi.camelkit.config.AgentConfig;
 import io.github.luigidemasi.camelkit.config.AgentRegistry;
@@ -14,6 +15,12 @@ import static org.junit.jupiter.api.Assertions.*;
 
 class ClaudeGeneratorTest {
 
+    private static final Set<String> INTERNAL_SKILLS = Set.of(
+            "camel-design",
+            "camel-implement",
+            "camel-test",
+            "camel-verify");
+
     @TempDir
     Path tempDir;
 
@@ -81,8 +88,6 @@ class ClaudeGeneratorTest {
             assertTrue(worker.contains("name: camel-ship-worker"));
             assertTrue(worker.contains("tools: Read, Grep, Glob"));
             assertFalse(worker.contains("mcpServers"));
-            String command = 
Files.readString(ctx.commandsDir().resolve("camel-ship.md"));
-            assertTrue(command.contains("Read 
.claude/skills/camel-ship/SKILL.md and follow those instructions"));
             String claudeMd = Files.readString(tempDir.resolve("CLAUDE.md"));
             assertTrue(claudeMd.contains("@AGENTS.md"),
                     "CLAUDE.md must import AGENTS.md via @AGENTS.md 
directive");
@@ -102,7 +107,54 @@ class ClaudeGeneratorTest {
         String content = Files.readString(brainstormSkill);
         assertTrue(content.contains("Dispatch"));
 
-        // Slash commands still exist
-        
assertTrue(Files.exists(ctx.commandsDir().resolve("camel-migrate.md")));
+        // Claude skills are discoverable natively — no duplicate command stubs
+        
assertFalse(Files.exists(ctx.commandsDir().resolve("camel-migrate.md")),
+                "Claude must not generate command stubs — skills are 
discoverable via frontmatter");
+    }
+
+    @Test
+    void marksInternalSkillsAsNotUserOrModelInvocableForClaude() throws 
Exception {
+        InitContext ctx = createContext();
+        new ClaudeGenerator().generate(ctx);
+
+        for (String skillName : INTERNAL_SKILLS) {
+            String skill = Files.readString(ctx.skillsDir().resolve(skillName 
+ "/SKILL.md"));
+            assertTrue(skill.contains("user-invocable: false"),
+                    skillName + " must declare user-invocable: false for 
Claude");
+            assertTrue(skill.contains("disable-model-invocation: true"),
+                    skillName + " must not be model invocable for Claude");
+        }
+
+        String start = 
Files.readString(ctx.skillsDir().resolve("camel-start/SKILL.md"));
+        assertFalse(start.contains("disable-model-invocation: true"),
+                "camel-start must remain model-invocable");
+    }
+
+    @Test
+    void addsHyphenatedUserInvocableMetadataForClaude() throws Exception {
+        InitContext ctx = createContext();
+        new ClaudeGenerator().generate(ctx);
+
+        String start = 
Files.readString(ctx.skillsDir().resolve("camel-start/SKILL.md"));
+        assertTrue(start.contains("user-invocable: true"),
+                "camel-start must have hyphenated user-invocable for Claude 
Code discovery");
+
+        String brainstorm = 
Files.readString(ctx.skillsDir().resolve("camel-brainstorm/SKILL.md"));
+        assertTrue(brainstorm.contains("user-invocable: false"),
+                "camel-brainstorm must have hyphenated user-invocable: false 
for Claude Code");
+    }
+
+    @Test
+    void skillDescriptionsAreClaudeCodeDiscoverable() throws Exception {
+        InitContext ctx = createContext();
+        new ClaudeGenerator().generate(ctx);
+
+        for (String skillName : Set.of("camel-start", "camel-brainstorm", 
"camel-migrate",
+                "camel-plan", "camel-execute", "camel-validate", "camel-ship",
+                "camel-knowledge", "camel-debug")) {
+            String skill = Files.readString(ctx.skillsDir().resolve(skillName 
+ "/SKILL.md"));
+            assertTrue(skill.contains("description: Use when"),
+                    skillName + " description must start with 'Use when' for 
Claude Code discovery");
+        }
     }
 }
diff --git 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ShippedAssetStructureTest.java
 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ShippedAssetStructureTest.java
index 09fdfc01..1859d4f6 100644
--- 
a/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ShippedAssetStructureTest.java
+++ 
b/camel-kit-core/src/test/java/io/github/luigidemasi/camelkit/generator/ShippedAssetStructureTest.java
@@ -45,6 +45,7 @@ class ShippedAssetStructureTest {
     // Command directories that non-stub agents historically used; generation 
must never recreate them.
     private static final Map<String, String> LEGACY_COMMAND_DIRS = Map.of(
             "antigravity", ".agents/commands",
+            "claude", ".claude/commands",
             "codex", ".codex/commands",
             "copilot", ".github/commands");
 
@@ -800,8 +801,6 @@ class ShippedAssetStructureTest {
                 assertTrue(skillContent.contains("Leave `model` and 
`isolation` unset"));
                 assertTrue(skillContent.contains("outside the project 
directory"));
                 assertFalse(skillContent.contains("`fork_context`"));
-                Path command = ctx.commandsDir().resolve("camel-ship.md");
-                assertTrue(Files.readString(command).contains("Read 
.claude/skills/camel-ship/SKILL.md"));
                 String worker = 
Files.readString(ctx.projectDir().resolve(".claude/agents/camel-ship-worker.md"));
                 assertTrue(worker.contains("\ntools: Read, Grep, Glob\n"));
                 assertFalse(worker.contains("mcpServers"));

Reply via email to