Skip to content

feat(skills): author skill services in azure.yaml - #9638

Open
Glenn Harper (glharper) wants to merge 3 commits into
mainfrom
glharper/9088-skill-authoring
Open

feat(skills): author skill services in azure.yaml#9638
Glenn Harper (glharper) wants to merge 3 commits into
mainfrom
glharper/9088-skill-authoring

Conversation

@glharper

Copy link
Copy Markdown
Member

Summary

Completes the authoring stage of #9088 after #9622 moved deploy-time reconciliation into azure.ai.skills.

Adds a dedicated declarative command:

azd ai skill add triage-rules --file ./skills/triage-rules
azd deploy triage-rules

skill add only writes azure.yaml; it does not create or update the remote Foundry skill. This avoids the remote-success/local-write-failure window discussed on #9116 and keeps azure.yaml as the source of truth.

What changed

  • Supports inline flags, SKILL.md, ZIP packages, and skill directories.
  • Creates new host: azure.ai.skill services with Project.Get + AddService.
  • Idempotently updates existing skill services with GetServiceConfigSection + SetServiceConfigSection.
  • Preserves uses:, project:, $ref, and unknown/unowned fields while clearing stale owned fields when switching between inline and archive content.
  • Rejects same-name services owned by another host instead of overwriting them.
  • Stores archive sources as forward-slash paths relative to the skill service directory and rejects lexical or symlink escapes.
  • Allows project: for azure.ai.skill in the v1.0 and alpha core schemas so documented service-relative paths are schema-valid.
  • Applies the 25 MB upload limit to generated directory archives as well as ZIP files.
  • Documents the declarative workflow and a valid agent dependency through uses:.

This supersedes the authoring portion of #9116 without adding the unresolved --save-to-azure-yaml dual-write behavior.

Validation

  • go test ./... -count=1, go build ./..., and golangci-lint run ./... in azure.ai.skills
  • Extension and core-schema spell checks
  • Core schema JSON parsing
  • mage checkDependencyVersions
  • mage preflight (all checks passed)

Add a declarative skill add command that creates or updates azure.ai.skill service blocks without mutating the remote resource. Preserve unowned service fields and write safe portable archive references.

Refs #9088

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6d1f6705-1953-4a0a-852c-0dae4541e1d8
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
20 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds declarative Foundry skill authoring to azure.yaml.

Changes:

  • Adds azd ai skill add.
  • Supports inline, SKILL.md, ZIP, and directory sources.
  • Adds schema, documentation, path-safety, and archive-size updates.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
schemas/v1.0/azure.yaml.json Allows skill service paths.
schemas/alpha/azure.yaml.json Mirrors schema support.
cli/azd/extensions/azure.ai.skills/README.md Documents declarative composition.
internal/exterrors/codes.go Adds manifest error codes.
internal/cmd/skill_update.go Reuses skill-file loading.
internal/cmd/skill_service_config.go Implements service upserts.
internal/cmd/skill_service_config_test.go Tests upserts and paths.
internal/cmd/skill_input.go Centralizes SKILL.md parsing.
internal/cmd/skill_create.go Reuses parsing helper.
internal/cmd/skill_add.go Adds the command.
internal/cmd/skill_add_test.go Tests command behavior.
internal/cmd/service_target.go Enforces archive size limits.
internal/cmd/service_target_test.go Tests size boundaries.
internal/cmd/root.go Registers skill add.
extension.yaml Adds command example.
Suppressed comments (1)

cli/azd/extensions/azure.ai.skills/internal/cmd/skill_add.go:105

  • A one-line SKILL.md body ending in .md or .txt is also stored as instruction text here, but reconciliation trims it and interprets it as a path. A valid body such as Follow README.md therefore becomes undeployable after skill add --file SKILL.md; retain an explicit inline/file distinction and add a regression test for this input shape. (azd-code-reviewer)
		declaration.Config = skillServiceConfig{
			Description:   parsed.Description,
			Instructions:  parsed.Instructions,

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cli/azd/extensions/azure.ai.skills/README.md
Comment on lines +79 to +81
declaration.Config = skillServiceConfig{
Description: a.flags.description,
Instructions: a.flags.instructions,
Co-authored-by: glharper <64209257+glharper@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

cli/azd/extensions/azure.ai.skills/internal/cmd/skill_add.go:112

  • This persisted archive reference makes the extension's contributor guidance inaccurate: cli/azd/extensions/azure.ai.skills/AGENTS.md:66-68 says --file is invocation-only and is never tracked or re-read. Update that section to distinguish declarative add archive/directory inputs, which are re-read during deploy, from remote create/update inputs.
	case modeFilePackage, modeFileDirectory:
		declaration.ArchiveSource = a.flags.file

cli/azd/extensions/azure.ai.skills/internal/cmd/service_target.go:506

  • This whitespace check makes valid references such as prompts/code review.md become literal instructions instead of loading the file. The skill schema allows .md/.txt paths without excluding spaces, so distinguish prose from a path without rejecting all whitespace and add coverage for a spaced filename.
	if strings.ContainsAny(value, " \t\r\n") {

Comment thread cli/azd/extensions/azure.ai.skills/internal/cmd/skill_service_config.go Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 20, 2026 02:00
@github-actions

Copy link
Copy Markdown

📋 Prioritization Note

Thanks for the contribution! The linked issue isn't in the current milestone yet.
Thank you for logging this issue; our team is reviewing it. If you need urgent prioritization, tag Rick Winter (@RickWinter) and Kristen Womack (@kristenwomack) to let us know.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Suppressed comments (3)

cli/azd/extensions/azure.ai.skills/internal/cmd/skill_service_config.go:282

  • [azd-code-reviewer] This line is not gofmt-formatted; gofmt -d changes it, so the repository's enforced formatting check (cli/azd/AGENTS.md:127) will fail. Run gofmt on this file.
return filepath.ToSlash(resolvedRelative), nil

cli/azd/extensions/azure.ai.skills/internal/cmd/service_target.go:506

  • [azd-code-reviewer] Treating any whitespace as proof that instructions is inline breaks valid .md/.txt paths containing spaces, including absolute paths, even though the schema documents this field as a file path. The heuristic also still misclassifies a one-token inline body such as README.md. Use an explicit file-versus-inline discriminator or another unambiguous syntax so both forms round-trip.
	if strings.ContainsAny(value, " \t\r\n") {

cli/azd/extensions/azure.ai.skills/internal/cmd/skill_service_config.go:238

  • [azd-code-reviewer] The new real-path containment check is the protection against an archive symlink escaping the service root, but the tests cover only a lexically outside path. Add cases for an in-root symlink pointing outside (rejected) and an in-root symlink pointing inside (accepted) so this path-safety boundary cannot regress.
	sourceReal, err := filepath.EvalSymlinks(sourceAbs)

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

azure.ai.skills PR build

Note

This is an unsigned development build. Install it only if you trust this PR.

Install the extension:

azd ext install "https://azuresdkartifacts.z5.web.core.windows.net/azd/extensions/pr/9638/azure-ai-skills.zip"
  • Version: 1.0.0-beta.3.pr.9638.6723262
  • Merge commit: 82fd364

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ext-skills azure.ai.skills extension

Projects

None yet

Development

Successfully merging this pull request may close these issues.

azure.ai.skills: own the azure.ai.skill service block in azure.yaml

3 participants