Skip to content

Commit 18c21d4

Browse files
leemthompoclaude
andauthored
fix: include repo prefix in agent skill install command (#3441)
The copy command was missing the repo prefix, generating `npx skills add @elasticsearch-esql` instead of `npx skills add elastic/agent-skills@elasticsearch-esql`. Closes #3439 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b9f1dea commit 18c21d4

4 files changed

Lines changed: 22 additions & 11 deletions

File tree

docs/syntax/agent-skill.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Agent skill
22

3-
The `{agent-skill}` directive renders a standardized callout that points readers to an [Elastic AI agent skill](https://github.com/elastic/agent-skills). When the URL includes a skill name (after `@`), it shows a "Copy install command" button that copies the `npx skills add @skill-name` command to clipboard. Otherwise, it falls back to a "Get the skill" link.
3+
The `{agent-skill}` directive renders a standardized callout that points readers to an [Elastic AI agent skill](https://github.com/elastic/agent-skills). When the URL includes a skill name (after `@`), it shows a "Copy install command" button that copies the `npx skills add owner/repo@skill-name` command to clipboard. Otherwise, it falls back to a "Get the skill" link.
44

55
## Usage
66

@@ -64,4 +64,4 @@ This skill helps agents write and optimize ES|QL queries.
6464

6565
The `:url:` property must be an absolute URL. Relative paths are not accepted, and the directive will emit a build error if the URL is missing or relative.
6666

67-
The skill name is extracted from the URL as the segment after the final `@`. For example, `https://github.com/elastic/agent-skills@elasticsearch-esql` produces the install command `npx skills add @elasticsearch-esql`.
67+
The skill name is extracted from the URL as the segment after the final `@`, and the repository prefix is extracted from the URL path. For example, `https://github.com/elastic/agent-skills@elasticsearch-esql` produces the install command `npx skills add elastic/agent-skills@elasticsearch-esql`.

src/Elastic.Markdown/Myst/Directives/AgentSkill/AgentSkillBlock.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ public class AgentSkillBlock(DirectiveBlockParser parser, ParserContext context)
1515

1616
public string? SkillName { get; private set; }
1717

18-
public string? InstallCommand => SkillName is not null ? $"npx skills add @{SkillName}" : null;
18+
public string? RepoPrefix { get; private set; }
19+
20+
public string? InstallCommand => SkillName is not null && RepoPrefix is not null
21+
? $"npx skills add {RepoPrefix}@{SkillName}"
22+
: null;
1923

2024
public override void FinalizeAndValidate(ParserContext context)
2125
{
@@ -25,17 +29,24 @@ public override void FinalizeAndValidate(ParserContext context)
2529
else if (!Uri.TryCreate(Url, UriKind.Absolute, out var uri) || uri.Scheme is not ("http" or "https"))
2630
this.EmitError($"agent-skill :url: must be an absolute URL, got '{Url}'");
2731
else
28-
SkillName = ExtractSkillName(uri);
32+
(RepoPrefix, SkillName) = ExtractSkillParts(uri);
2933
}
3034

31-
private static string? ExtractSkillName(Uri uri)
35+
private static (string? RepoPrefix, string? SkillName) ExtractSkillParts(Uri uri)
3236
{
3337
var path = uri.AbsolutePath.TrimEnd('/');
3438
var atIndex = path.LastIndexOf('@');
3539
if (atIndex < 0)
36-
return null;
40+
return (null, null);
3741

3842
var name = path[(atIndex + 1)..];
39-
return string.IsNullOrWhiteSpace(name) ? null : name;
43+
if (string.IsNullOrWhiteSpace(name))
44+
return (null, null);
45+
46+
var repoPath = path[1..atIndex].TrimEnd('/');
47+
if (string.IsNullOrWhiteSpace(repoPath))
48+
return (null, null);
49+
50+
return (repoPath, name);
4051
}
4152
}

tests/Elastic.Markdown.Tests/Directives/AgentSkillTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ A regular paragraph.
2626
public void SetsSkillName() => Block!.SkillName.Should().Be("elasticsearch-esql");
2727

2828
[Fact]
29-
public void SetsInstallCommand() => Block!.InstallCommand.Should().Be("npx skills add @elasticsearch-esql");
29+
public void SetsInstallCommand() => Block!.InstallCommand.Should().Be("npx skills add elastic/agent-skills@elasticsearch-esql");
3030

3131
[Fact]
3232
public void SetsDirective() => Block!.Directive.Should().Be("agent-skill");
@@ -59,7 +59,7 @@ public void RendersCopyButton()
5959
{
6060
Html.Should().Contain("class=\"agent-skill-button\"");
6161
Html.Should().Contain("Copy install command");
62-
Html.Should().Contain("data-copy-text=\"npx skills add @elasticsearch-esql\"");
62+
Html.Should().Contain("data-copy-text=\"npx skills add elastic/agent-skills@elasticsearch-esql\"");
6363
}
6464

6565
[Fact]

tests/authoring/Blocks/AgentSkill.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type ``agent skill with url`` () =
2828
<p>A skill is available to help AI agents with this topic.</p>
2929
<p><a href="/explore-analyze/ai-features/agent-skills#available-skills">Learn more about agent skills for Elastic</a></p>
3030
</div>
31-
<button type="button" class="agent-skill-button" data-copy-text="npx skills add @elasticsearch-esql">
31+
<button type="button" class="agent-skill-button" data-copy-text="npx skills add elastic/agent-skills@elasticsearch-esql">
3232
<svg class="agent-skill-button-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
3333
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z"></path>
3434
</svg>
@@ -66,7 +66,7 @@ This skill helps agents write and optimize ES|QL queries.
6666
<p>This skill helps agents write and optimize ES|QL queries.</p>
6767
<p><a href="/explore-analyze/ai-features/agent-skills#available-skills">Learn more about agent skills for Elastic</a></p>
6868
</div>
69-
<button type="button" class="agent-skill-button" data-copy-text="npx skills add @elasticsearch-esql">
69+
<button type="button" class="agent-skill-button" data-copy-text="npx skills add elastic/agent-skills@elasticsearch-esql">
7070
<svg class="agent-skill-button-icon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
7171
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 0 0-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75 2.25 2.25 0 0 0-.1-.664m-5.8 0A2.251 2.251 0 0 1 13.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V8.25m0 0H4.875c-.621 0-1.125.504-1.125 1.125v11.25c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V9.375c0-.621-.504-1.125-1.125-1.125H8.25ZM6.75 12h.008v.008H6.75V12Zm0 3h.008v.008H6.75V15Zm0 3h.008v.008H6.75V18Z"></path>
7272
</svg>

0 commit comments

Comments
 (0)