Skip to content

Bundle d365fo-cli guidance as a first-class Copilot skill - #127

Merged
dynamics365ninja merged 7 commits into
dynamics365ninja:mainfrom
RollPatrol:main
Aug 5, 2026
Merged

Bundle d365fo-cli guidance as a first-class Copilot skill#127
dynamics365ninja merged 7 commits into
dynamics365ninja:mainfrom
RollPatrol:main

Conversation

@RollPatrol

Copy link
Copy Markdown
Contributor

True lazy loaded skills to save on token usage and not be interjected into every prompt.

RollPatrol and others added 4 commits August 4, 2026 11:36
- Add skills/d365fo-cli/SKILL.md — core rule canon (renamed from
  .github/copilot-instructions.md) with SKILL frontmatter and updated
  resource table pointing to resources/
- Add skills/d365fo-cli/resources/*.md — 19 lazily-loaded X++ topic files
  emitted from skills/_source (frontmatter stripped)
- Update scripts/emit-skills.ps1 — add Emit-CopilotSkill function that
  writes body-only files to skills/d365fo-cli/resources/ as a third
  emit target alongside copilot and anthropic
- Update scripts/emit-skills.py — matching emit_copilot_skill() function
  for parity in Python environments
- Rewrite scripts/Install-D365FoCopilotSkills.ps1 — deploy skill folder
  (.github/skills/d365fo-cli/) instead of flat copilot-instructions.md +
  instructions/; adds migration notice for legacy files
- Update README.md, docs/SETUP.md, docs/EXAMPLES.md,
  docs/MIGRATION_FROM_MCP.md, docs/TROUBLESHOOTING.md — replace old
  copy-paste integration instructions with one-command skill installer
  and new skill layout description

The legacy skills/copilot/ and skills/anthropic/ outputs are still
emitted for non-skill consumers (documented as legacy paths).

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

Dalton stonessi create d365fo skill
Added strict "NEVER write X++ AOT XML files directly" warning block to all X++ authoring guidance files, instructing use of `d365fo generate ...` CLI commands only. Renamed all "resources/" references and folder structure to "references/" across scripts, SKILL.md, and documentation. Updated all related documentation, comments, and logic to reflect the new folder name and reinforce the supported authoring workflow. No other functional changes.
@dynamics365ninja

dynamics365ninja commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Audit — thanks, right direction, but a few blockers

The intent is good and the skill format is fundamentally valid (frontmatter checks out against the spec — see "What's good" at the bottom). But there are 4 blocking issues, one of which ships factually outdated X++ guidance.

Everything below was verified by checking out e7aab9b and actually running the scripts, not just reading the diff.


Blocking

1. Committed references/*.md are out of sync with skills/_source/ — 14 of 19 files

Checked out the PR head, ran python scripts/emit-skills.py, and git status reported 14 modified files (+175/−93). skills/copilot and skills/anthropic stayed clean — only the new target drifts.

This isn't whitespace, it's stale guidance. Example from references/label-translation.md:

-- `--lang` is required when the file does not embed a single language stem
+- `--lang` only affects path resolution when using `--install-to <MODEL>`; it
+  has no effect when `--file` is given directly

Root cause: references were generated in c346fd3, then main was merged in 418c5b2 (which corrected _source as part of the KB audit), but the emitter was never re-run. As it stands this PR would distribute guidance upstream already fixed.

Fix: re-run the emitter and commit the result.

2. The CI drift gate doesn't cover the new target.github/workflows/ci.yml:55

if [ -n "$(git status --porcelain skills/copilot skills/anthropic)" ]; then

skills/d365fo-cli/references is missing. That's exactly why #1 slipped through — please extend the path list (and the step name, which still says "Copilot + Anthropic") in the same PR, otherwise the drift will come back.

3. emit-skills.ps1 no longer runs on Windows PowerShell 5.1

$copilotSkillOut = Join-Path $OutRoot 'd365fo-cli' 'references'

The three-argument Join-Path (-AdditionalChildPath) only exists in PowerShell 6+. Verified under 5.1:

A positional parameter cannot be found that accepts argument 'references'.

Developer PowerShell for VS 2022 and a typical D365FO dev VM are both 5.1.

Fix: Join-Path (Join-Path $OutRoot 'd365fo-cli') 'references'

4. The installer now hard-depends on pwsh

& pwsh -NoProfile -File $emitScript

This replaces the previous python invocation, which degraded gracefully (Write-Warning + instructions to run it manually). pwsh is not present on a stock Windows box — verified missing on a clean Windows Server 2022 install, where the call raises CommandNotFoundException. Combined with $ErrorActionPreference = 'Stop', the installer aborts instead of warning.

Fix: probe pwshpowershellpython, or keep the python fallback.


Note — 5. Visual Studio 2022 does not support agent skills (retracted)

Corrected after maintainer feedback — this is not a blocker, and the "VS 2022 / 2026" claims in SKILL.md, README and SETUP.md can stay as they are.

I originally raised this from MS Learn's prerequisites ("Visual Studio 2026 version 18.5 or later"), reading it to mean that a VS 2022 user would end up with a skill their IDE cannot read and no fallback, since the installer stopped deploying copilot-instructions.md / instructions/. The maintainer has verified in practice that VS 2022 does load skills from .github/skills/ — it just isn't an officially documented path. So the regression I described doesn't exist.

One thing still worth a thought, purely as your call: undocumented behaviour carries no compatibility guarantee across Copilot extension updates, and skills/copilot/*.instructions.md is already emitted anyway — so a -Legacy switch on the installer would be cheap insurance rather than new work.


Medium

6. Inconsistent file writing between emitters. Emit-CopilotSkill uses Set-Content -Encoding utf8, while Emit-Copilot / Emit-Anthropic deliberately use [System.IO.File]::WriteAllText(..., $Utf8NoBom). Under Windows PowerShell 5.1, -Encoding utf8 means with BOM, so the output diverges from emit-skills.py and the CI gate (once #2 and #3 are fixed) will fail depending on who generated the files. Please use the same $Utf8NoBom path.

7. Dangling cross-references after the rename. .github/copilot-instructions.md is deleted, but these still point at it:

  • src/D365FO.Cli/Commands/Agent/AgentPromptCommand.cs:37 — the CLI's own output (d365fo agent-prompt) sends users to a file that no longer exists
  • docs/CAPABILITIES.md:378 and :452
  • docs/TOKEN_ECONOMICS.md:25 — still describes .instructions.md frontmatter, and token economics is the whole premise of this PR
  • docs/img/solution-architecture-diagram.svg:137
  • the emit-skills.ps1 header comment still says "emits two parallel artifacts"

8. README says SKILL.md is "always loaded". In the skills model only name + description stay in context; the body is loaded on activation. As written it contradicts the PR's own rationale ("not be interjected into every prompt").


Low

9. $referenceFiles.Count under Set-StrictMode -Version Latest throws The property 'Count' cannot be found on this object when references/ doesn't exist — i.e. exactly the "first run / clean clone" path the new .DESCRIPTION advertises. (The pattern is inherited from the old script, but it now sits on a newly promoted path.) @(Get-ChildItem ...).Count fixes it.

10. Install-D365FoCopilotSkills.ps1 has no BOM but contains and . Windows PowerShell 5.1 reads BOM-less files as ANSI, so the migration notice prints as mojibake.

11. The installer only copies references, never prunes — renamed or removed topics leave orphans behind in the target repo.

12. Losing the applyTo globs (19 path-scoped instruction files → one skill whose activation is a model decision) isn't a defect, but it's a deliberate trade-off worth stating in the PR description.


What's good

  • Frontmatter is spec-correct: name: d365fo-cli matches the directory, compatibility is a valid optional property, description is 347/1024 chars, SKILL.md is 165/500 lines.
  • Renaming resources/references/ in the last commit was the right call — that's the documented convention.
  • Both emitters (.ps1 and .py) were extended consistently, and SKILL.md is correctly preserved on regeneration (only references/ is removed).
  • The docs rewrite in the files you did touch is thorough and careful.

Sources: Use Agent Skills with GitHub Copilot — Visual Studio · Adding agent skills for GitHub Copilot — GitHub Docs

Follow-up to the PR dynamics365ninja#127 audit. Addresses the four blocking findings.

1. Regenerate skills/d365fo-cli/references/ from skills/_source/
   14 of 19 files were generated before the upstream main merge (418c5b2)
   and carried guidance the KB audit had already corrected - e.g. the
   --lang semantics of `labels create` and the EDT label-inheritance rule.

2. Extend the CI drift gate to the new emit target
   .github/workflows/ci.yml only diffed skills/copilot and skills/anthropic,
   which is why (1) went unnoticed. Adds skills/d365fo-cli/references.

3. Make emit-skills.ps1 run on Windows PowerShell 5.1
   - Join-Path $OutRoot 'd365fo-cli' 'references' used the 3-argument form
     (-AdditionalChildPath), which is PowerShell 6+ only.
   - $PSScriptRoot is empty when param() defaults are evaluated under 5.1,
     so Source/OutRoot are now resolved in the script body instead.
   - Emit-CopilotSkill used Set-Content -Encoding utf8, which writes a BOM
     under 5.1 and would diverge from emit-skills.py; it now uses the same
     $Utf8NoBom WriteAllText path as the other two emitters.
   - Progress output is ASCII: these files have no BOM (a BOM would break
     the #!/usr/bin/env pwsh shebang), so 5.1 reads them as ANSI.

4. Stop the installer from hard-requiring pwsh
   Install-D365FoCopilotSkills.ps1 called `& pwsh` unconditionally. A stock
   Windows / D365FO dev VM has no pwsh, so with $ErrorActionPreference =
   'Stop' the installer aborted with CommandNotFoundException instead of
   degrading. It now probes pwsh -> powershell -> python/python3 and warns
   only when none is available. Also wraps Get-ChildItem in @() so .Count
   stays valid under Set-StrictMode when references/ is absent.

Verified on Windows PowerShell 5.1: both emitters now produce byte-identical
output, the installer deploys SKILL.md + 19 references, and the clean-clone
regeneration path works.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfAAnxQDnPHRB1ne5H724n
@dynamics365ninja

Copy link
Copy Markdown
Owner

Follow-up: blocking items 1–4 fixed in 060dc8c

I've pushed the four blocking fixes straight to this branch rather than leaving you to redo them — hope that's helpful rather than intrusive. Revert or amend freely if you'd rather do it your own way.

060dc8c — 17 files, +231/−111.

# Item What changed
1 Stale references/ Regenerated from skills/_source/ — 14 files. Restores the KB-audit corrections the old snapshot was overwriting (--lang semantics on labels create, EDT label inheritance).
2 CI drift gate .github/workflows/ci.yml now diffs skills/d365fo-cli/references too, and the step name matches.
3 emit-skills.ps1 on PS 5.1 Nested Join-Path; plus two extra defects found while testing (below).
4 Installer's pwsh dependency Probes pwshpowershellpython/python3, warns only when none is found.

Two extra things surfaced while verifying #3

Worth flagging since they weren't in the original audit:

Also swapped the » and in console output for ASCII. These files carry no BOM, so 5.1 reads them as ANSI and mangles non-ASCII — and adding a BOM isn't an option, it would break the #!/usr/bin/env pwsh shebang. (Item #10, partially; the box-drawing characters in comments are untouched since they're never printed.)

Item #9 (@(Get-ChildItem ...) for .Count under Set-StrictMode) came along with the installer rewrite.

Verified on Windows PowerShell 5.1

Still open, for you

#7 dangling references to the deleted .github/copilot-instructions.mdAgentPromptCommand.cs:37 is the one that matters, since it's the CLI's own output. Then docs/CAPABILITIES.md:378/:452, docs/TOKEN_ECONOMICS.md:25, docs/img/solution-architecture-diagram.svg:137.

#8 the README's "always loaded" note on SKILL.md, #11 the installer never pruning stale references, #12 the applyTo trade-off in the PR description.

And #5 is retracted — see the edit on my earlier comment. VS 2022 does load .github/skills/, it's just undocumented.

dynamics365ninja and others added 2 commits August 5, 2026 07:06
…ynamics365ninja#8, dynamics365ninja#11

CI drift
  The `skills` job failed on the merge result, not on the branch: this PR
  last merged main at 418c5b2, and 012e018 ("correct remaining 5 KB files
  against live D365FO VM") has since changed three _source files. Merged
  main and regenerated, which updates exactly those three references:
  sysoperation-batch-patterns, table-scaffolding, x++-class-authoring.

  Worth noting for future rebases: the drift gate runs against
  refs/pull/N/merge, so a branch that is clean on its own can still fail
  once main moves the source files underneath it.

dynamics365ninja#7 Dangling references to the deleted .github/copilot-instructions.md
  - AgentPromptCommand.cs now points at skills/d365fo-cli/SKILL.md and
    names the install target. This one shipped in `d365fo agent-prompt`
    output, so it was sending users to a file that no longer exists.
  - docs/CAPABILITIES.md: the "Copilot Skills" section now describes the
    skill layout, and the source-file table lists all three emit targets.
  - docs/TOKEN_ECONOMICS.md: describes what the skill model actually costs
    (name + description until activation) instead of .instructions.md
    frontmatter, with the legacy figure kept as a parenthetical.
  - docs/img/solution-architecture-diagram.svg: .github/instructions/ ->
    .github/skills/d365fo-cli/.

dynamics365ninja#8 README "always loaded"
  Only name + description stay in context; the body is paged in on
  activation. Relabelled so the diagram doesn't contradict the PR's own
  token-economics rationale.

dynamics365ninja#11 Installer never pruned
  Install-D365FoCopilotSkills.ps1 now removes reference files in the target
  that no longer exist upstream, so renamed or retired topics stop feeding
  Copilot guidance the current skill has dropped. Reported in the summary
  line and documented in .DESCRIPTION and the README step list.

Verified: emitter output is drift-free against the merged _source, and the
installer prunes a planted stale reference while deploying SKILL.md + 19.
The C# change is text inside a raw string literal; it is not built here
(this machine has only .NET SDK 9, the solution targets 10) - CI covers it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfAAnxQDnPHRB1ne5H724n
@dynamics365ninja
dynamics365ninja merged commit 4c7a827 into dynamics365ninja:main Aug 5, 2026
4 checks passed
PeterCOSMO pushed a commit to PeterCOSMO/d365fo-cli that referenced this pull request Aug 5, 2026
dynamics365ninja#12)

Follow-up to PR dynamics365ninja#127. Both items were left open at merge time.

dynamics365ninja#10 Non-ASCII in Install-D365FoCopilotSkills.ps1
  The file has no BOM, so Windows PowerShell 5.1 reads it as ANSI. This is
  not just a comment-cosmetics issue: the em dashes sit in .PARAMETER and
  .EXAMPLE blocks, so `Get-Help` rendered them as mojibake -

      contains — or will contain — the .github/ directory

  All em dashes and box-drawing characters are now ASCII. Adding a BOM
  instead is not an option for these scripts: emit-skills.ps1 carries a
  #!/usr/bin/env pwsh shebang that a BOM would break, and keeping the two
  scripts encoded the same way is worth more than the typography.

  Also fixed the deletion hints in the migration notice: they suggested
  `Remove-Item -Recurse` for a file, and offered commands for paths that
  don't exist. Each hint is now printed only when its target is present,
  with -Recurse only on the directory.

dynamics365ninja#12 Skill activation is a judgement call, not a glob
  The skill replaces 19 .instructions.md files that applied deterministically
  via applyTo. A skill exposes only name + description and the agent decides
  relevance itself - that is what makes it cheap, but it is a real behaviour
  change and it was undocumented.

  docs/SETUP.md now explains this where users hit it, including how to force
  activation ("use the d365fo-cli skill", or naming a references/ file), where
  each IDE shows which skills were applied, and that skills/copilot/*.instructions.md
  is still emitted for anyone who wants the deterministic scoping back.

  The installer's legacy notice no longer flatly calls those files safe to
  delete, since that now contradicts documented advice - it says the skill
  supersedes and does not conflict with them, and points at SETUP.md.

Verified on Windows PowerShell 5.1: Get-Help renders clean ASCII, the
installer deploys SKILL.md + 19 references and prunes stale ones, and the
emitters remain drift-free.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfAAnxQDnPHRB1ne5H724n
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.

2 participants