DD

dynamics365ninja/d365fo-cli

Developer tools
34 stars 0 forks 品質 55 トレンド 55

CLI toolkit for Dynamics 365 Finance & Operations X++ development. Indexes AOT metadata, scaffolds objects, and wires up AI agents via a stable JSON envelope and MCP.

概要

Grounded AI development for Dynamics 365 Finance & Operations — works with GitHub Copilot, Claude Code, Codex, Gemini CLI, and any agent with a shell AI assistants excel at C#, Python, and JavaScript. X++ is different: your D365FO codebase is private, deeply customized, and invisible to every model — so AI confidently generates code that doesn't compile. This CLI pre-indexes your entire D365FO installation (hundreds of thousands of symbols across standard, ISV, and custom models) into a local SQLite index and exposes it as one d365fo binary. Every signature, every CoC wrapper, every label, every form pattern — verified against your real metadata the AI writes a single line. And because it is a shell command instead of an MCP tool list, it costs ~100 tokens per turn instead of ~1,800. Forms are the hardest artifact to generate correctly — each pattern dictates required containers, ordering, and allowed sub-patterns.

README

d365fo — AI-native CLI for D365 F&O X++


Why

AI assistants excel at C#, Python, and JavaScript. X++ is different: your D365FO codebase is private, deeply customized, and invisible to every model — so AI confidently generates code that doesn’t compile.

This CLI pre-indexes your entire D365FO installation (hundreds of thousands of symbols across standard, ISV, and custom models) into a local SQLite index and exposes it as one d365fo binary. Every signature, every CoC wrapper, every label, every form pattern — verified against your real metadata before the AI writes a single line. And because it is a shell command instead of an MCP tool list, it costs ~100 tokens per turn instead of ~1,800.

Task Without d365fo With d365fo
Method signatures Guessed → compile errors d365fo get class — exact, from your codebase
Existing CoC wrappers Manual AOT search d365fo find coc Class::method in < 50 ms
New forms Hand-written XML, broken patterns Pattern-validated scaffolds; structural violations block the write
Labels Hardcoded strings Right @SYS/@MODULE key found instantly
Security chains Hours of manual tracing Role → Duty → Privilege → Entry Point in one call
Generated code Hallucinated fields and types Every reference proven against the index, gated before write
Agent context cost 32 MCP tool schemas every turn (40 132 chars, ~11 100 tokens — measured) 1 shell tool + lazy-loaded Skills (366 chars, ~100 tokens)

Capabilities

Feature Description
🔍 Full-codebase intelligence Tables, classes, EDTs, enums, forms, queries, views, entities, reports, services, workflows, security artifacts, labels (FTS5) — results in milliseconds, no VM round-trip
🛡️ Grounded generation Fail-closed gates: prepare change/prepare create issue grounding tokens, validate references proves every identifier, validate xpp enforces BP rules — hallucinated code never reaches disk
🧩 Form pattern engine Catalog of Microsoft form patterns and container sub-patterns: get form-pattern serves the required structure, generate form self-tests against it (FP001–FP010), validate form-pattern re-checks any hand edit
✍️ Pattern-correct scaffolding 43 generate commands — tables, classes, CoC, forms (9 patterns), form datasource/control override methods, entities, security, SysOperation, workflows, business events, number sequences, XDS policies
🏗️ SDLC integration MSBuild compilation with structured xppcDiagnostics, DB sync, xppbp best practices, SysTestRunner — on Windows D365FO VMs
📐 X++ knowledge base 43 lazy-loaded Skills: select grammar, CoC authoring, FormRun lifecycle, BP rule canon — loaded only when relevant, for Copilot and Claude alike
Agent-first ergonomics Stable { ok, data, warnings } JSON envelope, search batch / get batch / prepare single-round aggregators, agent-prompt + schema manifests
🔌 Daemon & MCP adapter Warm-cache named-pipe daemon with file-system watcher; d365fo-mcp speaks JSON-RPC 2.0 over the same index for MCP-only hosts, over stdio or --http for a shared team deployment (API_KEY, MCP_SERVER_MODE)

Pattern-grounded form development

Forms are the hardest artifact to generate correctly — each pattern dictates required containers, ordering, and allowed sub-patterns. The form pattern engine makes it a guided pipeline:

flowchart LR
    A["find form-patterns(what do peers use?)"] --> B["get form-patternstructure + reference forms"]
    B --> C["generate form--pattern &lt;P&gt;"]
    C --> D["pattern self-testFP001–FP010"]
    D -->|clean| E["write + JSON summary"]
    D -->|errors| B
    F["hand-edited form XML"] --> G["validate form-patternexit 2 on errors"]

Structural violations (wrong order, missing container, disallowed control, misapplied sub-pattern) block the write while D365FO_FORM_PATTERN_ENFORCE=true (the default) — recommendations only warn.


Quick Start

Prerequisites

  • .NET SDK 10 (pinned in global.json)
  • Access to a D365 F&O PackagesLocalDirectory (local clone, Azure Files share, or Windows VM path)

Install

One line in PowerShell checks for the .NET SDK, clones the repo, publishes a self-contained d365fo binary onto PATH, and hands off to d365fo init — an interactive wizard that detects your PackagesLocalDirectory and asks the rest. Safe to re-run — an existing checkout is updated in place.

irm https://raw.githubusercontent.com/dynamics365ninja/d365fo-cli/main/install.ps1 | iex

macOS / Linux (read · search · scaffold only — build/sync/test/bp need a Windows D365FO VM):

curl -fsSL https://raw.githubusercontent.com/dynamics365ninja/d365fo-cli/main/install.sh | bash

First run

The installer above already ran d365fo init for you. What’s left is populating the index:

# Point at your packages folder (skip if 'd365fo init' found it already)
$env:D365FO_PACKAGES_PATH = "K:\AosService\PackagesLocalDirectory"

# Build + populate the index
d365fo index build
d365fo index extract

# Verify
d365fo doctor --output json
d365fo index status --output json

# Search
d365fo search table Cust --output json
d365fo get table CustTable --output json
d365fo get batch table:CustTable class:CustTableType edt:CustAccount --output json
d365fo find coc SalesTable::insert --output json
d365fo labels resolve @SYS12345 --lang en-us,cs

Ready to scaffold your first table, form, and CoC extension? Full walkthrough with every command: docs/SETUP.md — Step 6.


AI Agent Integration

GitHub Copilot (VS Code / Visual Studio)

The preferred method is the one-command skill installer — it deploys the bundled d365fo-cli Copilot skill (SKILL.md + 43 lazily-loaded topic references) into your X++ project’s .github/skills/d365fo-cli/ folder. Copilot auto-discovers skills in .github/skills/ with no extra configuration, on VS 2022 17.14+ as well as VS 2026. Point -XppRepo at the folder that holds the .sln you open: Visual Studio discovers skills next to the solution, not in parent folders. See SETUP.md for the multi-solution setup and the .instructions.md fallback.

# From the d365fo-cli repo's scripts folder:
.\Install-D365FoCopilotSkills.ps1 -XppRepo "K:\D365FO\MyProject"

The installer:

  1. Regenerates skills/d365fo-cli/references/ if needed, using whichever host is available (pwsh, Windows PowerShell, or python).
  2. Copies skills/d365fo-cli/SKILL.md and all references/*.md to /.github/skills/d365fo-cli/.
  3. Removes reference files in the target that no longer exist upstream, so retired topics don’t linger.
  4. Prints a migration note if the legacy copilot-instructions.md / instructions/ files still exist.

Skill layout installed into your X++ repo:

.github/
└── skills/
    └── d365fo-cli/
        ├── SKILL.md              # core rule canon + tool mapping (loaded when the skill activates)
        └── references/            # 43 X++ topic files, loaded per topic on demand
            ├── analytics-and-er.md
            ├── barcode-scanning.md
            ├── build-error-triage.md
            ├── business-events-authoring.md
            ├── coc-extension-authoring.md
            ├── custom-service-authoring.md
            ├── data-entity-scaffolding.md
            ├── document-attachments.md
            ├── event-handler-authoring.md
            ├── form-pattern-scaffolding.md
            ├── forms-and-navigation.md
            ├── global-class-statics.md
            ├── integration-dmf-dualwrite.md
            ├── integration-patterns.md
            ├── inventory-and-warehouse.md
            ├── label-translation.md
            ├── model-dependency-and-coupling.md
            ├── number-sequence-patterns.md
            ├── object-extension-authoring.md
            ├── performance-and-caching.md
            ├── posting-and-financials.md
            ├── rdl-design-expressions.md
            ├── report-print-destinations.md
            ├── review-and-checkpoint-workflow.md
            ├── runtime-frameworks.md
            ├── security-hierarchy-trace.md
            ├── security-modeling.md
            ├── ssrs-report-authoring.md
            ├── sysoperation-batch-patterns.md
            ├── system-objects.md
            ├── table-scaffolding.md
            ├── testing-and-quality.md
            ├── transactions-and-concurrency.md
            ├── warehouse-mobile-app.md
            ├── workflow-authoring.md
            ├── x++-class-authoring.md
            ├── xpp-best-practice-rules.md
            ├── xpp-class-and-method-rules.md
            ├── xpp-data-access-apis.md
            ├── xpp-database-queries.md
            ├── xpp-runtime-functions.md
            ├── xpp-runtime-types.md
            └── xpp-statement-and-type-rules.md

Legacy path (pre-skill format): If you previously used copilot-instructions.md + instructions/*.instructions.md, you can migrate by running the installer and then removing the old files:

Remove-Item "\.github\copilot-instructions.md" -ErrorAction SilentlyContinue
Remove-Item "\.github\instructions" -Recurse -ErrorAction SilentlyContinue

The legacy skills/copilot/*.instructions.md output is still emitted by emit-skills.ps1 / emit-skills.py for environments that cannot use the .github/skills/ format (e.g. GitHub Copilot versions that predate skill auto-discovery).

Claude Code / Claude Desktop

.\scripts\Install-D365FoClaudeSkills.ps1 -XppRepo "K:\D365FO\MyProject"

Installs one .claude/skills//SKILL.md per knowledge topic, and prunes topics retired upstream. Manual equivalent: python3 scripts/emit-skills.py then cp -r skills/anthropic/. /your-repo/.claude/skills/.

Codex CLI / Gemini CLI / Cursor

Reference the SKILL.md files from skills/anthropic/ in your session prompt or AGENTS.md.

MCP (Claude Desktop, Continue, VS Code MCP)

The bundled d365fo-mcp adapter speaks JSON-RPC 2.0 over the same index. Its tool surface is consolidated into 32 discriminator-based tools (e.g. search, get_object_info, get_method, labels, security_info, extension_info, object_patterns, generate_object, modify_method, analyze, models) — see docs/MIGRATION_FROM_MCP.md:

{
  "mcpServers": {
    "d365fo": {
      "command": "d365fo-mcp",
      "args": [],
      "env": { "D365FO_PACKAGES_PATH": "K:\\AosService\\PackagesLocalDirectory" }
    }
  }
}

Sharing one instance across a team instead of a local stdio process per developer? Run d365fo-mcp --http — see docs/MIGRATION_FROM_MCP.md for the API_KEY / MCP_SERVER_MODE (read-only shared instance + write-only local companion) deployment pattern.

Verify

Open the AI chat and ask:

What tables contain "CustAccount" field?

A d365fo search shell call returning results from your codebase = you’re connected.


Why CLI instead of MCP?

MCP servers inject every tool definition into the model’s context on every single turn. Tool consolidation trimmed that surface — the upstream MCP server went from ~61 per-type tools to 26 discriminator-based tools, and this repo’s adapter advertises 32 — but the schemas remain. Measured on this repository (scripts/measure-context-cost.py, see docs/TOKEN_ECONOMICS.md): those 32 schemas are 40 132 characters (~11 100 tokens) in context every turn, against 366 characters (~100 tokens) for the CLI’s one-skill layout. Characters are measured; tokens are approximate (chars ÷ 3.6).

MCP server CLI + Skills
Tool definitions per turn 32 tools, 40 132 chars (~11 100 tokens) 1 skill, 366 chars (~100 tokens)
Discovery round-trips 2–3 per task often 1 (d365fo prepare change)
Scriptable (shell, CI/CD) No Yes
Works in any AI harness No — MCP hosts only Yes — Copilot, Claude, Codex, Gemini, …
Per-turn context cost baseline ~99 % less (ratio does not depend on the tokenizer)

See docs/TOKEN_ECONOMICS.md for the full analysis and the cases where MCP still wins. Migrating from d365fo-mcp-server? Start with docs/MIGRATION_FROM_MCP.md.


Commands at a Glance

Group Commands
Prepare prepare change, prepare create, prepare test — single-round context aggregators returning a grounding token
Validate validate name, validate xpp (offline BP rules), validate references (anti-hallucination gate)
Index index build, index extract, index refresh, index status (incl. stale-index detection), index export, index import, index optimize, index history
Discover search any, search batch, search class|table|edt|enum|form|query|view|entity|report|service|workflow|label|business-event|security-policy|configuration-key|tile|workspace
Get get object, get batch (up to 10 objects per call), get table|class|edt|enum|form|menu-item|query|view|entity|report|service|business-event
Security security role|duty|privilege (artifacts), security coverage (Role → Duty → Privilege reach) — mirrors the MCP security_info tool
Form patterns form-pattern analyze (advisor), form-pattern spec (catalog), form-pattern validate (FP001–FP010) — mirrors the MCP object_patterns tool (domain=form)
Find find related, find coc, find relations, find usages, find extensions, find event-handlers, find references, find form-patterns, find batch-jobs (the extensibility ones mirror the MCP extension_info tool)
Read read class, read table, read form (= MCP get_method)
Generate generate table|table-relation|find-methods|class|coc|form|form-clone|datasource-method|control-method|simple-list|entity|extension|event-handler|privilege|duty|role|report|report-extension|sysoperation|number-sequence|workflow|menu-item|edt|enum|query|view|map|business-event|custom-service|migration-script|runbase|security-policy|systest|configuration-key|form-part|label-file|menu|resource|tile|workflow-category|composite-entity|aggregate-entity (43)
Labels labels search|resolve|info|create|rename|delete — search/resolve plus in-place *.label.txt edits, multi-language via --lang (mirrors the MCP labels tool)
Journal / undo undo [--steps N] [--dry-run], journal list, delete (kind/name, bridge or on-disk) — deterministic single-command rollback for every write path (mirrors the MCP undo_last_modification tool)
Modify modify property|method, modify add-field|add-enum-value|add-control, modify add-index|add-relation|add-field-group|add-delete-action, modify rename-field, modify add-query-range|remove-query-range, modify add-entry-point|remove-entry-point, seven modify remove-* forms, and modify batch (several changes in one read-edit-write) — 22 operations over all 41 bridge-writable kinds, extension-aware and journalled for undo
Patterns & rules mobile-pattern list|spec — warehouse scanner screens, and which of the two frameworks owns the flow · report-pattern list|spec — the seven SSRS shapes as recipes · table-pattern list|spec — table shapes and what each presets · bp-moniker validate|search|suppress|extract — Best-Practice rule monikers from names a real installation declares, never a guess
Analyze analyze completeness, analyze integration, analyze impact, lint, suggest edt, suggest extension, report-integrations
Review review diff
Models models list, models deps, models coupling
Agent agent-prompt, schema
Daemon daemon start|status|stop|warmup
Ops (Windows VM) build, sync, test run, bp check

One worked example per command: docs/EXAMPLES.md

When to use built-in editor tools vs. d365fo

One-line rule: if the file ends in .xml and is an AOT object → always d365fo. Everything else (config, scripts, docs) → standard editor tools.

When d365fo returns ok: false — report the error to the user and stop. Metadata read from open XML files does not substitute for the CLI. Never fall back to PowerShell / Python scripts to write AOT XML.

The full scenario-by-scenario decision table lives in docs/CAPABILITIES.md.


Documentation

Getting started Reference Operations
Quick start — five minutes to the first answer Capabilities — everything the tool does Troubleshooting
Setup — install, configure, verify Examples — one per command Configuration — env vars and profiles
Usage examples — whole tasks, end to end Architecture — index schema, AOT coverage, lint rules, daemon Custom models — your code, UDE and split trees
Migration from MCP MCP tools ↔ CLI — generated map MCP configuration — pointing a client at the adapter
Token economics — measured, not estimated Shared deployment — one instance for a team
Contributing
Testing — the four layers and every gate New command checklist
Knowledge authoring — the corpus and its audit Agent eval loop — self-improving eval harness (eval/README.md)
Backlog — what is knowingly missing Changelog · Security

Troubleshooting

Symptom Fix
PACKAGES_PATH_NOT_FOUND Set D365FO_PACKAGES_PATH or pass --packages
UNSUPPORTED_PLATFORM build / sync / test / bp require Windows + a D365FO dev VM
NO_INDEX Run d365fo index build then d365fo index extract
FORM_PATTERN_VIOLATION The generated/edited form breaks its pattern — d365fo form-pattern spec shows the required structure
Index appears stale after editing XML Run d365fo index refresh --model
Index file locked Stop any running d365fo daemon or d365fo-mcp process; WAL sidecar files (-wal, -shm) are normal

More in docs/TROUBLESHOOTING.md and docs/SETUP.md.


License

MIT. The sibling d365fo-mcp-server is also MIT.

Disclaimer

This project is an independent research effort and is not affiliated with, endorsed by, or associated with Microsoft or any other organization. It is provided as-is for educational and development purposes.

View this README on GitHub

インストール

This server does not publish a one-line install command.

Open the repository installation guide

設定

{ "mcpServers": { "d365fo": { "command": "d365fo-mcp", "args": [], "env": { "D365FO_PACKAGES_PATH": "K:\\AosService\\PackagesLocalDirectory" } } } }