feat(ai): add agent mode to emit instructions and skills#270
Draft
dmcilvaney wants to merge 8 commits into
Draft
feat(ai): add agent mode to emit instructions and skills#270dmcilvaney wants to merge 8 commits into
dmcilvaney wants to merge 8 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a new azldev docs agent command surface and an embedded agentskill registry so azldev can emit (and serve via MCP) version-matched AI agent skills and instruction wrappers, while tightening MCP server behavior to better support agent usage.
Changes:
- Add
docs agent install/showcommands to emit agent scaffolding and expose a read-only MCP tool (docs-agent-show) for loading skill content on demand. - Introduce
internal/app/azldev/agentskill/as the single embedded source of truth for skills/instructions (templates + registries + rendering). - Update MCP server implementation to serialize tool calls and propagate a read-only hint from Cobra annotations into MCP tool schemas.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scenario/snapshots/TestMCPServerMode_1.snap.json | Updates MCP snapshot for the new read-only docs-agent-show tool and schema changes. |
| internal/app/azldev/core/mcp/mcpserver.go | Serializes MCP tool execution and propagates read-only tool hints from command annotations. |
| internal/app/azldev/command.go | Adds read-only MCP annotation support via ExportAsReadOnlyMCPTool. |
| internal/app/azldev/cmds/docs/markdown.go | Stops exporting docs-markdown as an MCP tool. |
| internal/app/azldev/cmds/docs/docs.go | Registers the new docs agent command subtree. |
| internal/app/azldev/cmds/docs/agent.go | Implements azldev docs agent install/show and .vscode/mcp.json upsert logic. |
| internal/app/azldev/cmds/docs/agent_test.go | Adds unit tests for agent file emission and .vscode/mcp.json behavior. |
| internal/app/azldev/cmds/docs/agent_internal_test.go | Adds internal tests for binding resolution and skill drift guards. |
| internal/app/azldev/agentskill/doc.go | Documents the agentskill architecture and rendering model. |
| internal/app/azldev/agentskill/content/update-component.md.tmpl | Adds embedded skill template content for updating component locks. |
| internal/app/azldev/agentskill/content/skill-wrapper.md.tmpl | Adds wrapper template that redirects to the read-only MCP tool for full skill text. |
| internal/app/azldev/agentskill/content/remove-component.md.tmpl | Adds embedded skill template content for removing components. |
| internal/app/azldev/agentskill/content/overlays.md.tmpl | Adds embedded skill template content for overlays workflows and rules. |
| internal/app/azldev/agentskill/content/mock.md.tmpl | Adds embedded skill template content for mock chroot usage. |
| internal/app/azldev/agentskill/content/instruction-wrapper.md.tmpl | Adds instruction wrapper template for path-scoped guidance. |
| internal/app/azldev/agentskill/content/image.md.tmpl | Adds embedded skill template content for image workflows. |
| internal/app/azldev/agentskill/content/comp-toml.md.tmpl | Adds embedded skill template content for component TOML authoring. |
| internal/app/azldev/agentskill/content/build-component.md.tmpl | Adds embedded skill template content for build/debug workflows. |
| internal/app/azldev/agentskill/content/azldev.md.tmpl | Adds primary azldev overview skill template content. |
| internal/app/azldev/agentskill/content/add-component.md.tmpl | Adds embedded skill template content for adding components. |
| internal/app/azldev/agentskill/agentskill.go | Implements registries, rendering, layouts, and file emission for skills/instructions. |
| internal/app/azldev/agentskill/agentskill_test.go | Adds tests validating skill/instruction rendering and invariants. |
| docs/user/reference/cli/azldev_docs.md | Regenerates CLI docs to include azldev docs agent. |
| docs/user/reference/cli/azldev_docs_agent.md | Adds generated CLI docs for azldev docs agent. |
| docs/user/reference/cli/azldev_docs_agent_show.md | Adds generated CLI docs for azldev docs agent show. |
| docs/user/reference/cli/azldev_docs_agent_install.md | Adds generated CLI docs for azldev docs agent install. |
| docs/user/README.md | Adds user-docs index entry for AI agent setup. |
| docs/user/how-to/set-up-ai-agents.md | Adds user guide for emitting agent files and wiring MCP. |
| docs/developer/prds/agent-scaffolding.prd.md | Adds PRD describing broader agent scaffolding roadmap. |
| .github/instructions/agent-skills.instructions.md | Adds maintainer instructions for editing/validating embedded skills. |
| .github/copilot-instructions.md | Updates contributor guidance to note the new agentskill single source of truth. |
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+149
to
+152
| // Skills returns the registered skills in emission order. | ||
| func Skills() []Skill { | ||
| return skills | ||
| } |
Comment on lines
+258
to
+261
| // Instructions returns the registered instruction files in emission order. | ||
| func Instructions() []Instruction { | ||
| return instructions | ||
| } |
Accept the skill as a positional argument with shell completion, so `azldev docs agent show <TAB>` lists the valid skills instead of forcing you to guess and hit an error. Running with no skill now lists the available skills (browse) rather than erroring, and an unknown name reports the valid choices. The --skill flag is kept (it gives the docs-agent-show MCP tool a typed parameter and preserves back-compat) and also completes.
The add-component skill told agents to write prep-sources inspection output to
`$(mktemp -d)`, which lands in /tmp and conflicts with repos (e.g. azurelinux)
whose conventions forbid bare mktemp and require an in-project scratch dir. Add
a WorkDir binding resolved from Project.WorkDir (default build/work) and template
the scratch path as `{{ .WorkDir }}/scratch/<name>`, so the skill follows each
repo's configured, gitignored work directory instead of steering agents off it.
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+191
to
+197
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives | ||
| // each call its own Env, only expose read-only commands as MCP tools (do not add | ||
| // [azldev.ExportAsMCPTool] to commands that mutate state). |
Comment on lines
+149
to
+152
| // Skills returns the registered skills in emission order. | ||
| func Skills() []Skill { | ||
| return skills | ||
| } |
Comment on lines
+258
to
+261
| // Instructions returns the registered instruction files in emission order. | ||
| func Instructions() []Instruction { | ||
| return instructions | ||
| } |
Comment on lines
+53
to
+55
| 3. A little hand-written prose here is fine, if it helps direct agents to the right skill. Keep it short, and avoid | ||
| repeating the skill content. | ||
| 3. Keep the count-based tests happy: `Files()` emits one file per skill plus one per instruction. |
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+252
to
+253
| // ponytail: plain JSON only. A JSONC file with comments fails here with a clear error | ||
| // rather than being silently rewritten and losing the comments. |
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+269
to
+270
| // ponytail: plain JSON only. A JSONC file with comments fails here with a clear error | ||
| // rather than being silently rewritten and losing the comments. |
Comment on lines
+405
to
+406
| return "", nil, fmt.Errorf("unknown skill %q; choose one of: %s", | ||
| requested, strings.Join(names, ", ")) |
Comment on lines
+53
to
+55
| 3. A little hand-written prose here is fine, if it helps direct agents to the right skill. Keep it short, and avoid | ||
| repeating the skill content. | ||
| 3. Keep the count-based tests happy: `Files()` emits one file per skill plus one per instruction. |
Comment on lines
+191
to
+195
| // LIMITATION: the [azldev.Env] here is created once when the MCP server starts and is reused | ||
| // for every tool call. Per-call global flags parsed by this Execute (e.g. '--dry-run', | ||
| // '--project') update the App's flag fields but are NOT re-threaded into this reused Env, so | ||
| // env.DryRun() and the loaded config still reflect the server's startup values. As a result a | ||
| // mutating tool invoked with '--dry-run=true' would still write. Until the MCP rework gives |
Comment on lines
+277
to
+280
| servers, _ := config[serversKey].(map[string]any) | ||
| if servers == nil { | ||
| servers = map[string]any{} | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.