Skip to content

Commit ae28ea5

Browse files
therealjohnCopilot
andcommitted
ai.docs: add skill doc category, rename install command
Add a fourth doc category for the Foundry skill resource (the azure.ai.skills extension) alongside agent, connection, and toolbox. Four topics under skills/skill/: overview (versioning model, has_blob, CLI surface, endpoint resolution), manage (imperative CLI reference with Foundry-specific input rules in-context), share (cross-project download flows + safe-extract guarantees), consume (Hosted-agent runtime wiring via skill_directories and the redeploy flow). Rename azd ai doc skills install to azd ai doc install skill. The new install parent groups embedded-pack installers; the skill child still copies the bundled azd-ai-skill coding-agent pack into the user's project (flag surface unchanged). No backwards-compat alias since the extension is 0.0.1-preview. Also: update the embedded SKILL.md router with a foundry skills section and azd ai skill in allowed-tools; refresh README directory layout and examples; add CHANGELOG entry; add agentskills/repoint/repoints to cspell.yaml to mirror the azure.ai.skills extension. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 71e409a commit ae28ea5

18 files changed

Lines changed: 799 additions & 74 deletions
Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
11
# Release History
22

3-
## 0.0.1-preview - Initial Version
3+
## 0.0.1-preview - Initial Version
4+
5+
### Added
6+
7+
* `azd ai doc skill` command group with topics for the Foundry skill
8+
resource (`overview`, `manage`, `share`, `consume`). Covers the
9+
`azure.ai.skills` extension lifecycle: the versioned skill model
10+
(`default_version` / `latest_version`), the `azd ai skill` CLI
11+
reference, cross-project sharing via download / re-upload, and
12+
agent-side wiring (`skill_directories`) for Hosted agents.
13+
* `azd ai doc install` parent command group for embedded-pack
14+
installers, hosting the renamed `install skill` child below.
15+
16+
### Changed
17+
18+
* Renamed `azd ai doc skills install` to `azd ai doc install skill`.
19+
The new `install` parent groups embedded-pack installers; the `skill`
20+
child copies the bundled `azd-ai-skill` coding-agent pack into the
21+
user's project (the existing `--target` / `--path` / `--force` /
22+
`--output` flag surface is unchanged). No backwards-compatible alias.
23+
* The embedded `SKILL.md` router now lists the Foundry skill resource
24+
docs alongside agent / connection / toolbox docs and adds
25+
`azd ai skill` to the `allowed-tools` list.

cli/azd/extensions/azure.ai.docs/README.md

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,28 @@ azd ai doc agent initialize
2020
azd ai doc agent configure
2121
azd ai doc agent investigate
2222
azd ai doc agent operate
23+
24+
# List topics for the Foundry skill resource (azure.ai.skills)
25+
azd ai doc skill
26+
azd ai doc skill overview
27+
azd ai doc skill manage
28+
azd ai doc skill share
29+
azd ai doc skill consume
30+
31+
# Install the embedded azd-ai-skill coding-agent pack into the project
32+
azd ai doc install skill --target copilot
2333
```
2434

2535
Each topic is a contract an agent reads to drive the matching CLI
2636
commands: exact invocations, JSON shape examples, error codes,
2737
confirmation-envelope handling.
2838

39+
> Note: the `skill` doc category covers the **Foundry skill resource**
40+
> managed by the `azure.ai.skills` extension. It is intentionally
41+
> distinct from `install skill`, which copies the embedded
42+
> coding-agent pack (`azd-ai-skill`) into the user's project for tools
43+
> like Claude Code / GitHub Copilot.
44+
2945
## Local development
3046

3147
The first install in a new environment needs the full pack + publish +
@@ -59,20 +75,34 @@ internal/cmd/
5975
configure.md
6076
investigate.md
6177
operate.md
62-
toolbox/ <-- future: topics for azure.ai.toolboxes
78+
connection/ <-- topics for azure.ai.connections (today under azd ai agent connection)
79+
overview.md
80+
add.md
6381
...
64-
project/ <-- future: topics for azure.ai.projects
82+
toolbox/ <-- topics for azure.ai.toolboxes
83+
overview.md
84+
add.md
6585
...
66-
doc_index.go <-- docCategories table (one entry per skills/ subdir)
67-
doc_agent.go <-- per-extension subcommand
86+
skill/ <-- topics for azure.ai.skills (Foundry skill resource)
87+
overview.md
88+
manage.md
89+
share.md
90+
consume.md
91+
doc_catalog.go <-- docCategories table (one entry per skills/ subdir)
92+
doc_agent.go <-- per-extension subcommand (one per category)
93+
doc_connection.go
94+
doc_toolbox.go
95+
doc_skill.go
6896
```
6997

7098
To add a new sibling:
7199

72100
1. Drop `skills/<sibling>/<topic>.md` files into this extension.
73-
2. Add an entry to `docCategories` in `doc_index.go`.
74-
3. Add a `new<Sibling>Command()` constructor mirroring `newAgentCommand()`
75-
and register it in `root.go`.
101+
2. Add an entry to `docCategories` in `doc_catalog.go` (plus a
102+
`categoryExtensionName` case in `doc_renderer.go`).
103+
3. Add a `new<Sibling>Command()` constructor mirroring `newSkillCommand()`
104+
and register it (plus the matching `helpformat.Install` block) in
105+
`root.go`.
76106

77107
No coordination with the sibling extension is required; this extension is
78108
the source of truth for its agent-friendly docs.

cli/azd/extensions/azure.ai.docs/cspell.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ words:
4040
- tmpfs
4141
# Used in skill_install.go comments describing the JSON wire shape
4242
- parseable
43+
# Foundry-skills terms used in skill/* topic markdown bodies.
44+
# `agentskills` references the agentskills.io naming spec.
45+
# `repoint` / `repoints` describe the metadata-only default-version
46+
# update flow on Foundry skills (mirrors azure.ai.skills cspell.yaml).
47+
- agentskills
48+
- repoint
49+
- repoints
4350
overrides:
4451
- filename: internal/cmd/doc_catalog.go
4552
words:

cli/azd/extensions/azure.ai.docs/internal/cmd/doc_catalog.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,33 @@ var docCategories = []DocCategory{
174174
"Print the consumer-side runtime guide.": "azd ai doc toolbox consume",
175175
},
176176
},
177+
{
178+
Name: "skill",
179+
DisplayName: "Foundry skills (azure.ai.skills)",
180+
// Foundry skills are centrally-stored, versioned behavioral
181+
// guidelines a Hosted agent downloads and injects as
182+
// instructions. Managed via the `azd ai skill` CLI (from the
183+
// `azure.ai.skills` extension). Intentionally distinct from
184+
// the embedded `azd-ai-skill` pack installed by
185+
// `azd ai doc install skill` -- that is a coding-agent pack
186+
// consumed by tools like Claude Code / GitHub Copilot.
187+
Short: "Manage Foundry skills -- versioned, project-scoped behavioral guidelines a Hosted agent downloads and injects " +
188+
"(azure.ai.skills).",
189+
Preamble: []string{
190+
"Foundry skills are reusable behavioral guidelines stored centrally on a Foundry project. " +
191+
"A Hosted agent downloads them at build time and the agent runtime injects them as " +
192+
"additional instructions on every session.",
193+
"Use `azd ai doc skill <topic>` to print one topic's body in full. " +
194+
"Start with `overview` for the mental model, then `manage` for the CLI.",
195+
},
196+
Examples: map[string]string{
197+
"List topics for skills.": "azd ai doc skill",
198+
"Print the overview topic.": "azd ai doc skill overview",
199+
"Print the management CLI reference.": "azd ai doc skill manage",
200+
"Print the cross-project sharing recipes.": "azd ai doc skill share",
201+
"Print the hosted-agent consumption guide.": "azd ai doc skill consume",
202+
},
203+
},
177204
}
178205

179206
// init populates the Topics field of every DocCategory from the

cli/azd/extensions/azure.ai.docs/internal/cmd/doc_renderer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ func categoryExtensionName(cat DocCategory) string {
253253
return "azure.ai.connections"
254254
case "toolbox":
255255
return "azure.ai.agents"
256+
case "skill":
257+
return "azure.ai.skills"
256258
default:
257259
return fmt.Sprintf("azure.ai.%s", cat.Name)
258260
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
// doc_skill.go implements `azd ai doc skill [topic]` -- prints
5+
// embedded skill-friendly markdown from skills/skill/*.md. Mirrors
6+
// doc_agent.go / doc_connection.go / doc_toolbox.go; all four share
7+
// printCategoryTopic and the embedded skillsFS in doc_agent.go (via
8+
// the //go:embed skills/*/*.md glob).
9+
//
10+
// These are docs for the Foundry Skill resource (versioned,
11+
// project-scoped behavioral guidelines managed via `azd ai skill`
12+
// from the azure.ai.skills extension). They are intentionally
13+
// distinct from the embedded `azd-ai-skill` pack copied into the
14+
// user's project by `azd ai doc install skill`.
15+
//
16+
// Add a new topic by dropping a markdown file with front-matter into
17+
// skills/skill/; the catalog loader picks it up automatically.
18+
19+
package cmd
20+
21+
import (
22+
"fmt"
23+
24+
"github.com/spf13/cobra"
25+
)
26+
27+
// newSkillCommand returns `azd ai doc skill [topic]`. When invoked
28+
// with no positional arg, prints the skill topic list. When invoked
29+
// with a positional topic name, prints that topic body.
30+
//
31+
// Acts as a single entry point an agent uses to load just the slice of
32+
// Foundry skill docs it needs to drive the `azd ai skill` CLI and to
33+
// wire downloaded SKILL.md files into a Hosted agent.
34+
func newSkillCommand() *cobra.Command {
35+
cmd := &cobra.Command{
36+
Use: "skill [topic]",
37+
Short: "Print agent-friendly documentation for Foundry skills.",
38+
// Long is intentionally empty: the styled Description function
39+
// passed via helpformat.Install in root.go drives the --help
40+
// preamble (the same string the RunE prints below for direct
41+
// invocation). cmd.Example is also intentionally empty so
42+
// helpformat.Install's cmd.Example auto-migration does not
43+
// produce a duplicate Examples block alongside the Footer one
44+
// we wire in root.go.
45+
Args: cobra.MaximumNArgs(1),
46+
RunE: func(cmd *cobra.Command, args []string) error {
47+
if len(args) == 0 {
48+
cat := FindCategory("skill")
49+
if cat == nil {
50+
return fmt.Errorf("doc catalog: skill category not registered")
51+
}
52+
out := cmd.OutOrStdout()
53+
if _, err := fmt.Fprint(out, renderCatalogBody(*cat)); err != nil {
54+
return err
55+
}
56+
if _, err := fmt.Fprint(out, renderCatalogExamples(*cat)); err != nil {
57+
return err
58+
}
59+
return nil
60+
}
61+
return printCategoryTopic(cmd.OutOrStdout(), "skill", args[0])
62+
},
63+
}
64+
return cmd
65+
}

cli/azd/extensions/azure.ai.docs/internal/cmd/help_styling_test.go

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ func TestDocRootHelp_StyledSections(t *testing.T) {
6363
assert.Contains(t, out, "Print the samples topic body.",
6464
"third catalog example title missing")
6565

66-
// Cobra's Available Commands listing should include the 3 visible
67-
// leaves (agent, skills, version; metadata is reserved by the SDK
68-
// and may appear as well -- not asserted).
69-
for _, name := range []string{"agent", "skills", "version"} {
66+
// Cobra's Available Commands listing should include the visible
67+
// leaves (agent, connection, toolbox, skill, install, version;
68+
// metadata is reserved by the SDK and may appear as well -- not
69+
// asserted).
70+
for _, name := range []string{"agent", "connection", "toolbox", "skill", "install", "version"} {
7071
assert.True(t, strings.Contains(out, name),
7172
"Cobra subcommand list missing %q", name)
7273
}
@@ -99,21 +100,21 @@ func TestDocAgentHelp_Smoke(t *testing.T) {
99100
"first catalog example title missing")
100101
}
101102

102-
// TestDocSkillsInstallHelp_BulletPreambleAndExamples confirms the
103-
// long-form skill install command -- which has an existing Long
103+
// TestDocInstallSkillHelp_BulletPreambleAndExamples confirms the
104+
// long-form `install skill` command -- which has an existing Long
104105
// containing bullet items written into the cobra.Command literal --
105106
// renders those as plain text alongside the styled section headers
106107
// and migrated Examples. This is the "leave existing Long verbatim"
107108
// path: no Description override, just styling around it.
108-
func TestDocSkillsInstallHelp_BulletPreambleAndExamples(t *testing.T) {
109+
func TestDocInstallSkillHelp_BulletPreambleAndExamples(t *testing.T) {
109110
withColorDisabled(t)
110111

111-
out := helpOf(t, "skills", "install")
112+
out := helpOf(t, "install", "skill")
112113
assert.Contains(t, out, "Built-in targets:")
113114
assert.Contains(t, out, "Usage:")
114115
assert.Contains(t, out, "Flags:")
115-
assert.Contains(t, out, "--target", "install's --target flag should appear in Flags section")
116-
assert.Contains(t, out, "Examples:", "skills install has migrated examples")
116+
assert.Contains(t, out, "--target", "install skill's --target flag should appear in Flags section")
117+
assert.Contains(t, out, "Examples:", "install skill has migrated examples")
117118
}
118119

119120
// runE runs the root command with args (no --help) and returns the
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
// install.go is the parent command for `azd ai doc install ...`. Today it
5+
// hosts a single child (`skill`, which installs the embedded azd-ai-skill
6+
// coding-agent pack into the user's project), but the design keeps
7+
// "install" as its own subtree so future installable artifacts (e.g.
8+
// `install hooks`, `install workflows`) slot in without resurfacing the
9+
// install ergonomics.
10+
//
11+
// Note: the embedded pack installed by `azd ai doc install skill` is the
12+
// coding-agent skill consumed by tools like Claude Code / GitHub Copilot.
13+
// It is intentionally distinct from the Foundry Skill resource managed by
14+
// the `azure.ai.skills` extension (see `azd ai doc skill` for those
15+
// docs).
16+
17+
package cmd
18+
19+
import (
20+
"github.com/azure/azure-dev/cli/azd/pkg/azdext"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
// newInstallCommand returns the `azd ai doc install` parent command. The
25+
// parent has no RunE -- it just hangs the skill subcommand off the tree.
26+
// Help text doubles as the index of available verbs.
27+
func newInstallCommand(extCtx *azdext.ExtensionContext) *cobra.Command {
28+
cmd := &cobra.Command{
29+
Use: "install <command> [options]",
30+
Short: "Install agent-friendly packs into your project.",
31+
Long: `Install agent-friendly packs into your project so a coding agent
32+
(Claude Code, Codex, Gemini CLI, GitHub Copilot, Opencode, or a custom
33+
integration) can follow them.
34+
35+
Packs are read from this extension's embedded content; installing copies
36+
them into a tool-specific path under the current project (e.g.
37+
.claude/skills/azd-ai-skill/ for Claude Code).`,
38+
Example: ` # Install the AZD AI skill pack for GitHub Copilot
39+
azd ai doc install skill --target copilot
40+
41+
# Install for Claude Code (writes .claude/skills/azd-ai-skill/)
42+
azd ai doc install skill --target claude
43+
44+
# Install to a custom directory
45+
azd ai doc install skill --target custom --path .my-tool/skills/azd-ai`,
46+
}
47+
48+
cmd.AddCommand(newInstallSkillCommand(extCtx))
49+
50+
return cmd
51+
}

cli/azd/extensions/azure.ai.docs/internal/cmd/root.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ func NewRootCommand() *cobra.Command {
3939
rootCmd.AddCommand(newAgentCommand())
4040
rootCmd.AddCommand(newConnectionCommand())
4141
rootCmd.AddCommand(newToolboxCommand())
42-
rootCmd.AddCommand(newSkillsCommand(extCtx))
42+
rootCmd.AddCommand(newSkillCommand())
43+
rootCmd.AddCommand(newInstallCommand(extCtx))
4344
rootCmd.AddCommand(newVersionCommand(&extCtx.OutputFormat))
4445
rootCmd.AddCommand(newMetadataCommand(rootCmd))
4546

@@ -92,6 +93,18 @@ func NewRootCommand() *cobra.Command {
9293
}
9394
}
9495

96+
// Same wiring for the skill category command. Mirrors the agent /
97+
// connection / toolbox blocks above. doc_skill.go stays cobra-only.
98+
if skillCmd := findChild(rootCmd, "skill"); skillCmd != nil {
99+
if cat := FindCategory("skill"); cat != nil {
100+
c := *cat
101+
helpformat.Install(skillCmd, helpformat.Options{
102+
Description: func(*cobra.Command) string { return renderCatalogBody(c) },
103+
Footer: func(*cobra.Command) string { return renderCatalogExamples(c) },
104+
})
105+
}
106+
}
107+
95108
// Walk the rest of the tree (skills, version, metadata) and apply
96109
// default styling. InstallAll skips already-Installed commands so
97110
// root and agent (above) keep their custom Description/Footer.

cli/azd/extensions/azure.ai.docs/internal/cmd/root_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ func TestNewRootCommand_HasAgentSubcommand(t *testing.T) {
2020
}
2121
assert.Contains(t, names, "agent",
2222
"azd ai doc must expose the agent subgroup")
23+
assert.Contains(t, names, "connection",
24+
"azd ai doc must expose the connection subgroup")
25+
assert.Contains(t, names, "toolbox",
26+
"azd ai doc must expose the toolbox subgroup")
27+
assert.Contains(t, names, "skill",
28+
"azd ai doc must expose the skill subgroup (Foundry skill resource docs)")
29+
assert.Contains(t, names, "install",
30+
"azd ai doc must expose the install subgroup (embedded skill-pack installer)")
2331
}
2432

2533
func TestNewRootCommand_RunsIndexAsDefault(t *testing.T) {
@@ -60,6 +68,25 @@ func TestSkillsFS_HasAllAgentTopics(t *testing.T) {
6068
}, got)
6169
}
6270

71+
func TestSkillsFS_HasAllSkillTopics(t *testing.T) {
72+
// Pins the topic set for the Foundry skill resource docs (the
73+
// azure.ai.skills extension). A future drop or rename is a
74+
// deliberate test update -- topic names are the wire contract
75+
// callers rely on (`azd ai doc skill <topic>`).
76+
topics, err := loadCategoryTopics("skill")
77+
require.NoError(t, err)
78+
var got []string
79+
for _, top := range topics {
80+
got = append(got, top.Name)
81+
}
82+
assert.ElementsMatch(t, []string{
83+
"overview",
84+
"manage",
85+
"share",
86+
"consume",
87+
}, got)
88+
}
89+
6390
func TestPrintCategoryTopic_KnownTopicEmitsBody(t *testing.T) {
6491
var buf bytes.Buffer
6592
require.NoError(t, printCategoryTopic(&buf, "agent", "initialize"))

0 commit comments

Comments
 (0)