Skip to content

feat: add agent skills support for declarative agents - #15607

Closed
Sébastien Levert (sebastienlevert) wants to merge 50 commits into
OfficeDev:devfrom
sebastienlevert:feature/agent-skills-support
Closed

feat: add agent skills support for declarative agents#15607
Sébastien Levert (sebastienlevert) wants to merge 50 commits into
OfficeDev:devfrom
sebastienlevert:feature/agent-skills-support

Conversation

@sebastienlevert

@sebastienlevert Sébastien Levert (sebastienlevert) commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

Feature: https://msazure.visualstudio.com/Microsoft%20Teams%20Extensibility/_workitems/edit/37278479

Summary

This PR adds comprehensive Agent Skills support to the Microsoft 365 Agents Toolkit, enabling declarative agents to bundle reusable skill definitions. Skills are markdown-based instruction sets (SKILL.md files) that can be packaged within the appPackage and referenced from the declarative agent manifest.

What are Agent Skills?

Agent Skills allow declarative agent authors to decompose agent behavior into modular, reusable instruction bundles. Each skill:

  • Lives in a folder under appPackage/skills/{skill-name}/
  • Contains a SKILL.md file with frontmatter (name, description) and markdown instructions
  • Is referenced in the declarative agent manifest via the agent_skills property

Changes by Package

@microsoft/app-manifest (packages/manifest)

  • v1.7 Declarative Agent JSON schema with agent_skills as a first-class property
  • AgentSkillElement type: folder (required string)
  • Auto-generated TypeScript types from the new schema
  • Updated DeclarativeAgentManifestWrapper with full skill CRUD operations:
    • addSkill(), removeSkill(), getSkill(), hasSkill(), getSkills()
  • Schema validation support for the new manifest version
  • 51+ unit tests covering all manifest operations

@microsoft/teamsfx-core (packages/fx-core)

  • FxCore.addSkill() lifecycle method following the established addPlugin/addKnowledge patterns
  • Question flow (addSkillQuestionNode) with:
    • Skill name input with inline validation (letters, numbers, hyphens; duplicate detection)
    • Skill description input
    • Manifest file selector
  • copilotGptManifestUtils.addSkill() to update the DA manifest with new skill entries
  • Scaffolding: creates skills/{name}/SKILL.md with frontmatter and template content
  • --from flag for importing existing skill folders:
    • Validates folder name format (letters, numbers, hyphens only)
    • Validates SKILL.md exists in the folder
    • Validates name: frontmatter matches the folder name
    • Skips name/description prompts when --from is provided
  • Validation: max 10 skills per agent, skills must be within appPackage boundary
  • Warn-level confirmation dialog before modifying files (matching addPlugin pattern)
  • Success notification with "View agent manifest" button
  • 13 unit tests covering all paths

@microsoft/m365agentstoolkit-cli (packages/cli)

  • atk add skill CLI command with options:
    • --name — Skill name (required for new skills)
    • --description — Skill description (required for new skills)
    • --from — Import existing skill folder
    • --manifest-file — App manifest path (defaults to ./appPackage/manifest.json)

VS Code Extension (packages/vscode-extension)

  • "Add Skill" tree view item in the Development section (lightbulb icon)
    • Only visible for declarative agent projects (isDeclarativeCopilotApp)
    • Positioned after "Add Action" in the tree
  • fx-extension.addSkill command with proper enablement conditions
  • Localization keys added across all 16 locale files
  • Full quickpick-based UX flow (no modal dialogs for questions)

CLI Usage Examples

# Create a new skill (interactive)
atk add skill -i

# Create a new skill (non-interactive)
atk add skill --name my-search-skill --description "Searches internal docs"

# Import an existing skill folder
atk add skill --from skills/existing-skill

Validation Rules

Rule Error
Skill name must match ^[a-zA-Z][a-zA-Z0-9-]*$ Inline validation error
Skill folder already exists "A skill named 'X' already exists"
Max 10 skills per agent SkillLimitExceeded
Skill folder must be within appPackage SkillOutsideAppPackage
SKILL.md must exist (for --from) SkillMdNotFound
SKILL.md name must match folder name (for --from) SkillNameMismatch
Folder name format (for --from) InvalidSkillFolderName

Testing

  • Manifest package: 51+ unit tests (schema validation, wrapper CRUD, converters)
  • FxCore: 13 unit tests (scaffolding, validation, error paths, confirm dialog, --from)
  • All tests passing locally

Add end-to-end support for agent skills in M365 Agents Toolkit:

- Manifest wrapper: AgentSkillElement, CRUD operations (add/remove/has/get),
  max 10 skills, x-agent_skills extension property with agent_skills fallback
- Packaging: bundle skill directories in createAppPackage, validate path
  boundary and SKILL.md existence
- Validation: skill folder/SKILL.md/frontmatter validation, error aggregation,
  telemetry, log formatting for CLI and VS Code
- FxCore.addSkill(): new/existing skill flows, SKILL.md template generation,
  path normalization, confirmation dialog
- Question flow: skill name, description, expose-to-copilot questions
- CLI: atk add skill command with options and telemetry
- VS Code: handler, command registration, telemetry events
- Localization: all English strings for prompts and messages
- Tests: 51 new unit tests across wrapper, packaging, validation, and command

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ore conflict

- Rename checkCopilotAccess.title to checkCopilotAccess in all 16 nls files
  to match the %teamstoolkit.commands.checkCopilotAccess% reference in package.json
- Remove redundant 'files' property from package.json since .vscodeignore
  is used for vsce packaging (newer vsce rejects having both)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add TreeViewCommand for addSkill below Add Action in the Development pane
- Add fx-extension.addSkill command entry in package.json with enablement
- Add localization keys (title, description, running, blockTooltip) across all 16 locales
- Remove diagnostic logging from localizeUtils.ts and treeViewCommand.ts
- Skill item shows only for declarative agent projects (isDeclarativeCopilotApp)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace ConfirmQuestion with SingleSelectQuestion (yes/no options)
- Update FxCore.addSkill to compare string 'yes' instead of boolean
- Add localization keys for yes/no options
- Update CLI option type from boolean to string
- Update tests accordingly - all 11 passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The addSkill flow had a showMessage() confirm dialog before proceeding,
which interrupted the quickpick-only UX. Remove it so the flow stays
entirely within the VS Code quickpick area.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds back the warn-level showMessage confirmation (matching addPlugin
pattern) that asks users to confirm before modifying files. This was
accidentally removed when the pre-action confirmation was stripped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Allow uppercase letters in skill names (not just lowercase)
- Validate for duplicate skill names (check if folder already exists)
- Rename CLI flags: --name, --description, --expose-to-copilot, --from
- Update validation error messages and placeholder text

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When adding an existing skill via --from, the name and description are
already in the SKILL.md file, so they shouldn't be required. Skip the
name/description prompts in the question flow when --from is provided.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When importing an existing skill via --from:
- Validate folder name uses only letters, numbers, and hyphens
- Read SKILL.md frontmatter and verify the name matches the folder name
- Error out with clear messages if either check fails

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienlevert
Sébastien Levert (sebastienlevert) changed the base branch from main to dev March 27, 2026 01:11
Add AgentSkillsEnabled feature flag (default: false) following the
established pattern (like EmbeddedKnowledge before cleanup). Gates:
- VS Code tree view item (treeViewManager.ts)
- VS Code command enablement (package.json)
- VS Code context (extension.ts setContext)
- CLI 'atk add skill' command (add.ts)

Set TEAMSFX_AGENT_SKILLS=true to enable the feature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add re-export of AgentSkillElement interface so it can be imported by
consumers and test files. Previously the type was imported from
generated-types and used internally but not re-exported, causing
TS2459 errors in the manifest test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

@tecton Ning Tang (tecton) 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.

I met "(×) Error: unknown.InternalError: The "path" argument must be of type string. Received undefined" when running atk new skill under DA project. Could you please fix it?

Comment thread packages/vscode-extension/package.nls.cs.json Outdated
Comment thread packages/fx-core/src/core/FxCore.ts
Comment thread packages/fx-core/src/core/FxCore.ts
@sebastienlevert

Copy link
Copy Markdown
Contributor Author

I met "(×) Error: unknown.InternalError: The "path" argument must be of type string. Received undefined" when running atk new skill under DA project. Could you please fix it?

Do you mean atk add skill?

@tecton

Copy link
Copy Markdown
Contributor

I met "(×) Error: unknown.InternalError: The "path" argument must be of type string. Received undefined" when running atk new skill under DA project. Could you please fix it?

Do you mean atk add skill?

Yes, sorry it's a typo.
image

@sebastienlevert

Copy link
Copy Markdown
Contributor Author

Please make sure you have the environment variable available.

$env:TEAMSFX_AGENT_SKILLS = "true"

I can run it locally here

image

- Use path.resolve(projectPath, teamsManifestPath) for manifest file
  resolution to handle both absolute and relative paths correctly
- Revert localized package.nls.*.json files (pipeline handles translations)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update treeViewManager test to expect 9 items (Add Skill added)
- Apply prettier formatting to CopilotGptManifestUtils and test files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented Mar 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.15738% with 20 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.16%. Comparing base (1bff6ff) to head (0a338e1).

Files with missing lines Patch % Lines
packages/fx-core/src/core/FxCore.ts 95.15% 7 Missing and 1 partial ⚠️
packages/cli/src/commands/models/addSkill.ts 54.54% 5 Missing ⚠️
...ore/src/question/scaffold/vsc/CapabilityOptions.ts 0.00% 2 Missing and 1 partial ⚠️
packages/cli/src/commands/models/add.ts 75.00% 0 Missing and 1 partial ⚠️
...t/driver/teamsApp/utils/CopilotGptManifestUtils.ts 98.50% 0 Missing and 1 partial ⚠️
.../fx-core/src/component/driver/teamsApp/validate.ts 88.88% 0 Missing and 1 partial ⚠️
...vscode-extension/src/handlers/lifecycleHandlers.ts 83.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##              dev   #15607      +/-   ##
==========================================
+ Coverage   93.14%   93.16%   +0.02%     
==========================================
  Files         608      610       +2     
  Lines       36866    37273     +407     
  Branches     6890     6892       +2     
==========================================
+ Hits        34339    34726     +387     
- Misses       1882     1897      +15     
- Partials      645      650       +5     
Files with missing lines Coverage Δ
packages/cli/src/telemetry/cliTelemetryEvents.ts 100.00% <100.00%> (ø)
packages/fx-core/src/common/featureFlags.ts 100.00% <ø> (ø)
.../src/component/driver/teamsApp/createAppPackage.ts 98.40% <100.00%> (+0.09%) ⬆️
...e/src/component/driver/teamsApp/utils/telemetry.ts 100.00% <100.00%> (ø)
.../component/generator/declarativeAgent/generator.ts 97.56% <ø> (ø)
...src/component/generator/templates/templateNames.ts 100.00% <100.00%> (ø)
...kages/fx-core/src/component/m365/packageService.ts 98.50% <100.00%> (+0.03%) ⬆️
packages/fx-core/src/error/teamsApp.ts 100.00% <100.00%> (ø)
packages/fx-core/src/question/index.ts 97.22% <100.00%> (+0.07%) ⬆️
packages/fx-core/src/question/inputs/index.ts 100.00% <100.00%> (ø)
... and 20 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

- Merge upstream/dev to stay current
- Fix CopilotGptManifestUtils.ts formatting (CI lint-pr.sh)
- Add 5 new unit tests for addSkill coverage gaps:
  - copilotExtensions manifest format path
  - Skill outside appPackage validation
  - SKILL.md without name frontmatter
  - showMessage error handling
  - DA manifest with empty file property

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add 7 tests for addSkillQuestionNode (pattern validation, duplicates, conditions)
- Add 4 tests for logValidationErrors with skill errors (VSC + CLI)
- Add 1 test for validate driver with non-empty skillValidationResult
- Remove 3 unused NLS keys (expose.description, from.title, from.placeholder)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Test VSCode View Agent Manifest button triggers openFile
- Test CLI platform success message path
- Test logValidationErrors with undefined skillValidationResult (covers ?? [] partials)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a new 'Declarative Agent with Skill' project template that includes
a pre-wired writing-coach agent skill. The skill is declared in the DA
manifest's agent_skills array and includes a SKILL.md with instructions
for reviewing and improving written content.

- New template: declarative-agent-with-skill (common language)
- Writing coach skill: grammar, clarity, tone, structure, conciseness
- Registered in question tree, metadata, and DA generator
- Available in both VS Code and CLI project creation flows

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Swap to a minimal hello-world skill that complements the existing
instruction.txt greeting. The skill adds a fun fact about today's date,
keeping the template simple and instantly demonstrating how skills work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@qfai

qfai commented May 22, 2026

Copy link
Copy Markdown
Contributor

could you resolve these PR Gate?

- Fix 9 skill validation tests using wrong stub (ManifestUtil.validateManifest
  -> AppManifestUtils.validateAgainstSchema)
- Apply ESLint formatting fixes to createAppPackage.ts, FxCore.ts,
  FxCore.addSkill.test.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add addSkillHandler test in VS Code lifecycleHandlers
- Add Teams manifest agentSkills packaging tests in createAppPackage
- Add CLI addSkill command test
- Add expose-to-copilot deduplication and boolean handling tests
- Add addSkill to MockCore for VS Code tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace predictable os.tmpdir() + Date.now() pattern with
fs.mkdtemp() which creates a unique directory atomically,
resolving CodeQL insecure-temporary-file alert.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienlevert

Copy link
Copy Markdown
Contributor Author

qfai we should be good now!

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.

I find teams schema v1.28 has the field now, do you want to change it to 1.28?

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.

remove these unnecessary changes

Comment thread templates/src/ui/da.ts
@qfai

qfai commented May 25, 2026

Copy link
Copy Markdown
Contributor

Sébastien Levert (@sebastienlevert) Our cut bit schedule for the next pre-release is 2026-06-02, let's try to merge it before cut bit :)

…ocalized nls files

- Add featureFlag: TEAMSFX_AGENT_SKILLS to the 'skill' option in templates/src/ui/da.ts so the entry is hidden until the manifest is ready (mirrors the existing TEAMSFX_DA_METAOS pattern in the same file).

- Gate DACapabilityOptions.withSkill() behind featureFlagManager.getBooleanValue(FeatureFlags.AgentSkillsEnabled) so the runtime VS Code wizard also hides the skill option when the feature flag is off.

- Restore non-English packages/vscode-extension/package.nls.*.json files to upstream/dev: only package.nls.json should be modified in PRs; the localization pipeline updates the other locales.

Addresses qfai review comments on PR OfficeDev#15607.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Picks up the v1.28 schema upgrade (PR OfficeDev#15986) which natively includes the agentSkills field, addressing qfai's review comment that the Teams schema v1.28 already has the field.

Conflict resolutions:

- packages/fx-core/src/common/featureFlags.ts: consolidated AgentSkillsEnabled (ours) and AgentSkillsManifest (upstream PR OfficeDev#15953) into a single AgentSkillsManifest flag with defaultValue: 'false' (per qfai's gating request). Removed our duplicate AgentSkillsEnabled name+flag.

- packages/fx-core/src/component/driver/teamsApp/createAppPackage.ts: kept upstream's cleaner addAgentSkillFolders helper instead of HEAD's inline dedup logic; now gated by AgentSkillsManifest flag.

- packages/cli/src/telemetry/cliTelemetryEvents.ts: kept both AddSkill (ours) and ImportOpenPlugin/ExportOpenPlugin (upstream).

- All non-English packages/vscode-extension/package.nls.*.json files: took upstream's version (per qfai's review).

- packages/manifest/src/generated-types/teams/TeamsManifestVDevPreview.ts: took upstream's regenerated version.

Other updates:

- Renamed all FeatureFlags.AgentSkillsEnabled usages to FeatureFlags.AgentSkillsManifest across vscode-extension, cli, and fx-core.

- Upgraded templates/vsc/common/declarative-agent-with-skill/appPackage/manifest.json.tpl from manifest v1.27 to v1.28 to match other templates.

- Updated createAppPackage.test.ts Teams manifest agentSkills tests to stub the AgentSkillsManifest flag to true (it now defaults false).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…am merge

- Restore SKILL.md presence check inside addAgentSkillFolders. Upstream's helper only validated the skill folder existed; this PR's intent is to require a SKILL.md file inside every skill folder (matching the existing DA-level agent_skills validation and the agentskills.io spec).

- Remove duplicate 'import * as path from path' in createAppPackage.test.ts.

- Stub fs.realpath in the 'should return error when skill path escapes appPackage boundary' test: upstream/dev's validateReferencedFile now calls fs.realpath which throws ENOENT for the synthetic '../../../outside' path used by the test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@sebastienlevert

Copy link
Copy Markdown
Contributor Author

Thanks for the review qfai! Addressed your comments in commits a189a73, 8e9d909, and 5a08e70:

  1. vDevPreview schema / v1.28 - Merged upstream/dev which already added the v1.28 schema (Update App Manifest schema version to v1.28 in all active templates and manifest package #15986) with the agentSkills field natively. Reverted our vDevPreview modification and upgraded the new declarative-agent-with-skill template manifest from v1.27 to v1.28 to match the other templates.

  2. Localized package.nls.*.json files - Reverted all non-English packages/vscode-extension/package.nls.*.json files to upstream/dev. Only package.nls.json is modified now.

  3. Feature flag for the skill entry - Added a TEAMSFX_AGENT_SKILLS gate in three places:

    • templates/src/ui/da.ts (JSON UI tree entry uses featureFlag: 'TEAMSFX_AGENT_SKILLS')
    • packages/fx-core/src/question/scaffold/vsc/CapabilityOptions.ts (DACapabilityOptions.all() now conditionally includes withSkill())
    • packages/vscode-extension/src/treeview/treeViewManager.ts and extension.ts (already wired)

    Consolidated with the existing FeatureFlags.AgentSkillsManifest (added upstream in feat: add atk import/export openplugin for interop with OpenPlugins #15953) so there's a single flag. Changed its default from true to false so all UI entries are hidden until the feature is ready, per your comment.

agent_skills will only ship in the DA v1.8 schema. v1.7 stays as it shipped in upstream/dev (no agent_skills).

Changes:

- Revert packages/manifest/src/json-schemas/copilot/declarative-agent/v1.7/schema.json to upstream/dev (removes the agent_skills property and agent-skill-object definition this PR previously added).

- Add packages/manifest/src/json-schemas/copilot/declarative-agent/v1.8/schema.json: copy of v1.7 with version constant changed to 'v1.8' and the agent_skills array + agent-skill-object definition (max 10 items, each with a required 'folder' string).

- Regenerate packages/manifest/src/generated-types/copilot/declarative-agent/DeclarativeAgentManifestV1D{7,8}.ts via node convert.js. V1D7 no longer exposes AgentSkillElement; V1D8 owns it.

- packages/manifest/src/generated-types/index.ts: add DeclarativeAgentManifestV1D8 import/export, the v1.8 entry in daConverterMap, switch DeclarativeAgentManifestLatest to V1D8, and re-export AgentSkillElement from V1D8 so wrappers/consumers keep working unchanged.

- templates/vsc/common/declarative-agent-with-skill/appPackage/declarativeAgent.json.tpl: bump \ URL and version field from v1.7 to v1.8 (this template is the only one that emits agent_skills).

Verified: 164 manifest tests pass, 165 fx-core addSkill/createAppPackage/copilotGptManifest tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
return { props, additional };
}

function m(additional: any) {
Audit of qfai's request 'add feature flag to hide these entry before manifest ready' showed two unprotected paths plus the FxCore entry. Closes the remaining gaps so nothing related to agent skills runs when TEAMSFX_AGENT_SKILLS is off.

Changes:

- packages/fx-core/src/component/driver/teamsApp/createAppPackage.ts: wrap the DA-level agent_skills folder packaging (lines 416-448) in a featureFlagManager.getBooleanValue(FeatureFlags.AgentSkillsManifest) check, matching the Teams manifest agentSkills gate added earlier. Now both paths refuse to copy skill folders into the zip when the flag is off.

- packages/fx-core/src/core/FxCore.ts: add an early flag check at the top of addSkill that returns a UserError 'AgentSkillsDisabled' when the flag is off, so programmatic callers (CLI invoked without the env var, custom scripts, future entry points) cannot bypass the gating that's already in place on the CLI registration and VS Code tree view/enablement.

- packages/fx-core/resource/package.nls.json: new core.addSkill.featureFlagDisabled string for the error above.

- tests/component/driver/teamsApp/createAppPackage.test.ts: add a beforeEach in the 'agent skills bundling' describe that stubs featureFlagManager.getBooleanValue so the DA-level tests keep passing now that the path is gated.

- tests/core/FxCore.addSkill.test.ts: stub featureFlagManager.getBooleanValue in the top-level beforeEach (so existing tests continue to exercise the enabled path) and add a new test that restores the stub and verifies addSkill returns a UserError('AgentSkillsDisabled') when the flag is off.

Verified: 166 fx-core agent-skill tests pass (+1 new). All other gating points were already covered (templates/src/ui/da.ts JSON option, DACapabilityOptions.withSkill, cli add.ts, treeViewManager, extension.ts isAgentSkillsEnabled context, package.json command enablement).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
qfai added a commit that referenced this pull request Jun 10, 2026
) (#16112)

* feat: add agent skills support for declarative agents

Add end-to-end support for agent skills in M365 Agents Toolkit:

- Manifest wrapper: AgentSkillElement, CRUD operations (add/remove/has/get),
  max 10 skills, x-agent_skills extension property with agent_skills fallback
- Packaging: bundle skill directories in createAppPackage, validate path
  boundary and SKILL.md existence
- Validation: skill folder/SKILL.md/frontmatter validation, error aggregation,
  telemetry, log formatting for CLI and VS Code
- FxCore.addSkill(): new/existing skill flows, SKILL.md template generation,
  path normalization, confirmation dialog
- Question flow: skill name, description, expose-to-copilot questions
- CLI: atk add skill command with options and telemetry
- VS Code: handler, command registration, telemetry events
- Localization: all English strings for prompts and messages
- Tests: 51 new unit tests across wrapper, packaging, validation, and command

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(vsc): fix VSIX packaging - mismatched nls key and files/vscodeignore conflict

- Rename checkCopilotAccess.title to checkCopilotAccess in all 16 nls files
  to match the %teamstoolkit.commands.checkCopilotAccess% reference in package.json
- Remove redundant 'files' property from package.json since .vscodeignore
  is used for vsce packaging (newer vsce rejects having both)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(vscode): add 'Add Skill' tree view item in Development section

- Add TreeViewCommand for addSkill below Add Action in the Development pane
- Add fx-extension.addSkill command entry in package.json with enablement
- Add localization keys (title, description, running, blockTooltip) across all 16 locales
- Remove diagnostic logging from localizeUtils.ts and treeViewCommand.ts
- Skill item shows only for declarative agent projects (isDeclarativeCopilotApp)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: change expose-to-copilot from confirm to Yes/No quickpick

- Replace ConfirmQuestion with SingleSelectQuestion (yes/no options)
- Update FxCore.addSkill to compare string 'yes' instead of boolean
- Add localization keys for yes/no options
- Update CLI option type from boolean to string
- Update tests accordingly - all 11 passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(vscode): use lightbulb icon for Add Skill tree item

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: remove pre-action confirm dialog from addSkill flow

The addSkill flow had a showMessage() confirm dialog before proceeding,
which interrupted the quickpick-only UX. Remove it so the flow stays
entirely within the VS Code quickpick area.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: restore confirm dialog before modifying DA manifest in addSkill

Adds back the warn-level showMessage confirmation (matching addPlugin
pattern) that asks users to confirm before modifying files. This was
accidentally removed when the pre-action confirmation was stripped.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: improve skill name validation and simplify CLI flags

- Allow uppercase letters in skill names (not just lowercase)
- Validate for duplicate skill names (check if folder already exists)
- Rename CLI flags: --name, --description, --expose-to-copilot, --from
- Update validation error messages and placeholder text

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: make --name and --description optional when using --from

When adding an existing skill via --from, the name and description are
already in the SKILL.md file, so they shouldn't be required. Skip the
name/description prompts in the question flow when --from is provided.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: validate folder name and SKILL.md name match for --from

When importing an existing skill via --from:
- Validate folder name uses only letters, numbers, and hyphens
- Read SKILL.md frontmatter and verify the name matches the folder name
- Error out with clear messages if either check fails

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: gate agent skills behind TEAMSFX_AGENT_SKILLS feature flag

Add AgentSkillsEnabled feature flag (default: false) following the
established pattern (like EmbeddedKnowledge before cleanup). Gates:
- VS Code tree view item (treeViewManager.ts)
- VS Code command enablement (package.json)
- VS Code context (extension.ts setContext)
- CLI 'atk add skill' command (add.ts)

Set TEAMSFX_AGENT_SKILLS=true to enable the feature.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: apply prettier formatting

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: export AgentSkillElement from DeclarativeAgentManifestWrapper

Add re-export of AgentSkillElement interface so it can be imported by
consumers and test files. Previously the type was imported from
generated-types and used internally but not re-exported, causing
TS2459 errors in the manifest test suite.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* style: apply prettier formatting across all packages

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: resolve PR review comments

- Use path.resolve(projectPath, teamsManifestPath) for manifest file
  resolution to handle both absolute and relative paths correctly
- Revert localized package.nls.*.json files (pipeline handles translations)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: CI formatting and tree view test count

- Update treeViewManager test to expect 9 items (Add Skill added)
- Apply prettier formatting to CopilotGptManifestUtils and test files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: merge dev, fix formatting, add coverage tests

- Merge upstream/dev to stay current
- Fix CopilotGptManifestUtils.ts formatting (CI lint-pr.sh)
- Add 5 new unit tests for addSkill coverage gaps:
  - copilotExtensions manifest format path
  - Skill outside appPackage validation
  - SKILL.md without name frontmatter
  - showMessage error handling
  - DA manifest with empty file property

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add coverage tests for skill questions, validation, and log errors

- Add 7 tests for addSkillQuestionNode (pattern validation, duplicates, conditions)
- Add 4 tests for logValidationErrors with skill errors (VSC + CLI)
- Add 1 test for validate driver with non-empty skillValidationResult
- Remove 3 unused NLS keys (expose.description, from.title, from.placeholder)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add coverage for VSCode .then() callback and undefined skill partials

- Test VSCode View Agent Manifest button triggers openFile
- Test CLI platform success message path
- Test logValidationErrors with undefined skillValidationResult (covers ?? [] partials)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix skill folders not included in app package

Skill folder paths were resolved relative to the DA manifest file
location, which points to .generated/ during packaging. Since skill
folders don't support env var substitution, they only exist in the
original appPackage/ directory.

Resolve skill folders relative to appDirectory instead, matching the
pattern used by embedded knowledge files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: support x-agent_skills fallback in app package creation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add zip import support for agent skills

Add ability to import skills from .zip files via UI (source type picker +
file dialog) and CLI (--from flag with .zip path). Includes:

- New SkillSourceType and SkillFromZipFile questions
- importSkillFromZip method with security validation (path traversal,
  zip bomb protection), layout detection, and atomic extraction
- NLS strings for UI labels and error messages
- 8 new tests covering zip import happy path and error cases

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add configurable max package size limit to zipAppPackage action

Cherry-picked from feature/zip-package-size-limit branch:
- Add configurable maxPackageSizeInBytes to CreateAppPackageArgs
- Enforce 10 MB package size limit on MOS/Titles API uploads
- Validate package size before parsing zip
- Enforce hard 10 MB package size limit on zipAppPackage action

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: enforce 10 MB package size limit on MOS/Titles API uploads

Add a validatePackageSize check in PackageService.sideLoading and
sideLoadXmlManifest that throws AppPackageSizeExceeded when the zip
exceeds the 10 MB MOS API limit. This prevents uploads that would
be rejected server-side with an unhelpful error.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: validate package size before parsing zip and fix test stubs

- Move validatePackageSize() before getManifestFromZip() in sideLoading
  to reject oversized files before attempting to parse them
- Add fs.statSync stub to beforeEach so existing tests are not broken
  by the new validation call
- Restore and re-stub in size-exceeded tests to override the default

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: remove MOS API reference from package size error message

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: enforce hard 10 MB package size limit on zipAppPackage action

Remove configurable maxPackageSizeInBytes option and always enforce
the 10 MB limit at build time, matching the install-time enforcement.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: remove expose_to_copilot property and all related options

Remove the expose_skill_to_copilot property from agent skills as this
feature is being deprecated. This removes:

- Schema property from DA manifest v1.7
- Generated types and converter mappings
- Deprecated types interface field
- CLI question and option for expose-to-copilot
- FxCore addSkill parameter
- CopilotGptManifestUtils addSkill parameter
- DeclarativeAgentManifestWrapper addSkill parameter
- All related localization strings
- All related test cases and fixtures
- Merge conflict markers in localization files

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: zip path traversal test now uses binary-patched zip

AdmZip normalizes '../' away during addFile/writeZip, so the original
test's traversal entry was silently stripped, causing ZipNoSkillMd
instead of ZipInvalidEntries. Fix by binary-patching the zip buffer
to preserve the traversal path in the entry name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add --expose-to-copilot option for agent skills in Teams manifest

Add support for exposing agent skills to all Copilot surfaces via the
top-level Teams manifest agentSkills property (devPreview schema).

When adding a skill, users can now opt into exposing it to Copilot:
- CLI: --expose-to-copilot switch
- VS Code: confirm dialog

If enabled, the skill folder is written to BOTH the DA manifest
(agent_skills, scoped to that agent) and the Teams manifest
(agentSkills, exposed to all Copilot surfaces).

Changes:
- Add agentSkills to devPreview Teams manifest JSON schema
- Regenerate types and export AgentSkill from generated-types
- Add skill CRUD methods to TeamsManifestWrapper
- Add agentSkills to legacy TeamsAppManifest type
- Add ExposeToCopilot question with --expose-to-copilot CLI switch
- Update FxCore.addSkill() to conditionally write Teams manifest
- Update createAppPackage to package skills from Teams manifest
- Add tests for expose-to-copilot flow and wrapper skill methods

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: register --expose-to-copilot CLI option in AddSkillOptions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: use quick pick instead of message box for expose-to-copilot

Change the expose-to-copilot question from a ConfirmQuestion (message box)
to a SingleSelectQuestion (quick pick) with Yes/No options in VS Code.
CLI still uses --expose-to-copilot boolean flag. Both values are handled
in FxCore.addSkill().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: use single-line quick pick for expose-to-copilot

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* revert: restore two-line quick pick for expose-to-copilot

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat: add Declarative Agent with Skill template

Add a new 'Declarative Agent with Skill' project template that includes
a pre-wired writing-coach agent skill. The skill is declared in the DA
manifest's agent_skills array and includes a SKILL.md with instructions
for reviewing and improving written content.

- New template: declarative-agent-with-skill (common language)
- Writing coach skill: grammar, clarity, tone, structure, conciseness
- Registered in question tree, metadata, and DA generator
- Available in both VS Code and CLI project creation flows

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: replace writing-coach skill with hello-world in template

Swap to a minimal hello-world skill that complements the existing
instruction.txt greeting. The skill adds a fun fact about today's date,
keeping the template simple and instantly demonstrating how skills work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* refactor: rename skill to hello-atk with Copilot fun facts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: resolve CI failures - fix test stubs and formatting

- Fix 9 skill validation tests using wrong stub (ManifestUtil.validateManifest
  -> AppManifestUtils.validateAgainstSchema)
- Apply ESLint formatting fixes to createAppPackage.ts, FxCore.ts,
  FxCore.addSkill.test.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test: add missing test coverage for agent skills feature

- Add addSkillHandler test in VS Code lifecycleHandlers
- Add Teams manifest agentSkills packaging tests in createAppPackage
- Add CLI addSkill command test
- Add expose-to-copilot deduplication and boolean handling tests
- Add addSkill to MockCore for VS Code tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: use path.join for cross-platform test compatibility

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: use fs.mkdtemp for secure temp directory creation

Replace predictable os.tmpdir() + Date.now() pattern with
fs.mkdtemp() which creates a unique directory atomically,
resolving CodeQL insecure-temporary-file alert.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: gate skill option behind TEAMSFX_AGENT_SKILLS flag and restore localized nls files

- Add featureFlag: TEAMSFX_AGENT_SKILLS to the 'skill' option in templates/src/ui/da.ts so the entry is hidden until the manifest is ready (mirrors the existing TEAMSFX_DA_METAOS pattern in the same file).

- Gate DACapabilityOptions.withSkill() behind featureFlagManager.getBooleanValue(FeatureFlags.AgentSkillsEnabled) so the runtime VS Code wizard also hides the skill option when the feature flag is off.

- Restore non-English packages/vscode-extension/package.nls.*.json files to upstream/dev: only package.nls.json should be modified in PRs; the localization pipeline updates the other locales.

Addresses qfai review comments on PR #15607.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: preserve SKILL.md validation and add realpath stubs after upstream merge

- Restore SKILL.md presence check inside addAgentSkillFolders. Upstream's helper only validated the skill folder existed; this PR's intent is to require a SKILL.md file inside every skill folder (matching the existing DA-level agent_skills validation and the agentskills.io spec).

- Remove duplicate 'import * as path from path' in createAppPackage.test.ts.

- Stub fs.realpath in the 'should return error when skill path escapes appPackage boundary' test: upstream/dev's validateReferencedFile now calls fs.realpath which throws ENOENT for the synthetic '../../../outside' path used by the test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(manifest): move agent_skills from DA v1.7 to new DA v1.8 schema

agent_skills will only ship in the DA v1.8 schema. v1.7 stays as it shipped in upstream/dev (no agent_skills).

Changes:

- Revert packages/manifest/src/json-schemas/copilot/declarative-agent/v1.7/schema.json to upstream/dev (removes the agent_skills property and agent-skill-object definition this PR previously added).

- Add packages/manifest/src/json-schemas/copilot/declarative-agent/v1.8/schema.json: copy of v1.7 with version constant changed to 'v1.8' and the agent_skills array + agent-skill-object definition (max 10 items, each with a required 'folder' string).

- Regenerate packages/manifest/src/generated-types/copilot/declarative-agent/DeclarativeAgentManifestV1D{7,8}.ts via node convert.js. V1D7 no longer exposes AgentSkillElement; V1D8 owns it.

- packages/manifest/src/generated-types/index.ts: add DeclarativeAgentManifestV1D8 import/export, the v1.8 entry in daConverterMap, switch DeclarativeAgentManifestLatest to V1D8, and re-export AgentSkillElement from V1D8 so wrappers/consumers keep working unchanged.

- templates/vsc/common/declarative-agent-with-skill/appPackage/declarativeAgent.json.tpl: bump \ URL and version field from v1.7 to v1.8 (this template is the only one that emits agent_skills).

Verified: 164 manifest tests pass, 165 fx-core addSkill/createAppPackage/copilotGptManifest tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: gate all agent skills code paths behind TEAMSFX_AGENT_SKILLS

Audit of qfai's request 'add feature flag to hide these entry before manifest ready' showed two unprotected paths plus the FxCore entry. Closes the remaining gaps so nothing related to agent skills runs when TEAMSFX_AGENT_SKILLS is off.

Changes:

- packages/fx-core/src/component/driver/teamsApp/createAppPackage.ts: wrap the DA-level agent_skills folder packaging (lines 416-448) in a featureFlagManager.getBooleanValue(FeatureFlags.AgentSkillsManifest) check, matching the Teams manifest agentSkills gate added earlier. Now both paths refuse to copy skill folders into the zip when the flag is off.

- packages/fx-core/src/core/FxCore.ts: add an early flag check at the top of addSkill that returns a UserError 'AgentSkillsDisabled' when the flag is off, so programmatic callers (CLI invoked without the env var, custom scripts, future entry points) cannot bypass the gating that's already in place on the CLI registration and VS Code tree view/enablement.

- packages/fx-core/resource/package.nls.json: new core.addSkill.featureFlagDisabled string for the error above.

- tests/component/driver/teamsApp/createAppPackage.test.ts: add a beforeEach in the 'agent skills bundling' describe that stubs featureFlagManager.getBooleanValue so the DA-level tests keep passing now that the path is gated.

- tests/core/FxCore.addSkill.test.ts: stub featureFlagManager.getBooleanValue in the top-level beforeEach (so existing tests continue to exercise the enabled path) and add a new test that restores the stub and verifies addSkill returns a UserError('AgentSkillsDisabled') when the flag is off.

Verified: 166 fx-core agent-skill tests pass (+1 new). All other gating points were already covered (templates/src/ui/da.ts JSON option, DACapabilityOptions.withSkill, cli add.ts, treeViewManager, extension.ts isAgentSkillsEnabled context, package.json command enablement).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: regenerate wizard NLS bundles and apply prettier formatting

- Regenerate packages/fx-core/templates/ui/{wizardNode,tdpNode}.json via 'cd templates && npm run build:vsc' so they stay in sync with templates/src/ui/.
- Apply prettier formatting to createAppPackage.test.ts and extension.ts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* revert: restore CRLF on localized package.nls.*.json

The PR accidentally rewrote 13 localized NLS files from CRLF to LF, which
fights the OneLocBuild pipeline and the eol=crlf rule for
'packages/vscode-extension/package.nls.*.json' in .gitattributes.

Reset all localized package.nls.<locale>.json files to origin/dev. The
English package.nls.json (LF, per the standard *.json rule) retains the
new content keys for agent skills.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Sébastien Levert <slevert@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@qfai

qfai commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

close this pr as we have merged in #16151

@qfai qfai closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants