mcpField
A
acad-dotnet

acad-dotnet

github.com/autodesk-platform-servicesDevelopment3187 installsUpdated 3w ago
Repository

About acad-dotnet

acad-dotnet is an agent skill for creating AutoCAD .NET plugin projects end to end, aimed at developers building for AutoCAD, Civil 3D, or Plant 3D. It covers scaffolding, project configuration, building, desktop and headless testing, and plugin packaging.

Key features

  1. 01Select templates and dependencies by target product
  2. 02Configure .NET framework and platform settings
  3. 03Set launch profiles and build the plugin
  4. 04Test with NETLOAD or accoreconsole
  5. 05Package desktop plugins or Design Automation bundles

Use cases

  1. 01Scaffold an AutoCAD or Civil 3D plugin project
  2. 02Run local headless tests with accoreconsole
  3. 03Prepare a plugin bundle for desktop loading or Design Automation

MCP support

The README does not mention MCP.

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/autodesk-platform-services/skills --skill acad-dotnet

After installing, type/acad-dotnetin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

README.md
references/
autocad-api.md
civil3d-api.md
code-sleuth.md
learnings.md
plant3d-api.md
templates/acad/
ClassName.cs
README.md
RootNamespace.csproj
templates/acad/.template.config/
template.json
templates/acad/RootNamespace.bundle/
PackageContents.xml
templates/acad/RootNamespace.bundle/Contents/
.gitkeep
templates/civil/
.gitignore
LICENSE
ReadMe.md
templates/civil/Civil/
CivilClassLib.csproj
Cmd.cs
templates/civil/Civil/.template.config/
template.json

Details

From the project README

Scaffold Skill — AutoCAD .NET Plugins

Agentic steps to create a new plugin project end-to-end. Execute these steps in order. All csproj patterns here are verified against AutoCAD 2027 / .NET 10.

Step 0 — Identify the target product

User saysTargetTemplateExtra packages
"AutoCAD plugin" / "acad add-in"AutoCAD 2027acadAutoCAD.NET 26.0.0
"Civil 3D plugin" / "c3d add-in"Civil 3D 2027civilCivil3D.NET 13.9.628
"Plant 3D plugin" / "plant add-in"Plant 3D 2027(manual)AutoCAD.NET.Core 26.0.0 + SDK DLL refs
"Design Automation" / "DA"Any (headless)acadUse .Core + .Model only (no AcMgd)

Step 1 — Scaffold

AutoCAD
dotnet new acad -n <ProjectName> -o <ProjectName>
cd <ProjectName>
Civil 3D
dotnet new civil --rootNamespace=<ProjectName> -o <ProjectName>
cd <ProjectName>
Plant 3D (manual)

Create <ProjectName>/<ProjectName>.csproj — see Plant 3D section below.


Step 2 — Fix csproj (CRITICAL)

Templates may generate outdated or incorrect settings. Apply all of these fixes:

Target framework

If the template generated net8.0-windows or net6.0-windows, change to net10.0-windows.

Platform target — x64 preferred over RuntimeIdentifier
<!-- WRONG for most plugins — creates RID subfolder, assembly won't load in AutoCAD -->
<RuntimeIdentifier>win-x64</RuntimeIdentifier>

<!-- CORRECT — outputs to bin\Debug\net10.0-windows\ (no RID subfolder) -->
<PlatformTarget>x64</PlatformTarget>

Why: AutoCAD probes for assemblies in the direct output folder. RuntimeIdentifier creates a win-x64 subfolder that AutoCAD/accoreconsole doesn't search by default. Exception: If you are importing cross-platform native NuGet packages (like Oracle or SQLite), you do need <RuntimeIdentifier>win-x64</RuntimeIdentifier> to fetch the correct windows binaries. In this rare case, also add <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> to your csproj to prevent the output from being pushed into an unreachable subfolder.

GenerateTargetFrameworkAttribute
<GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>

Prevents conflict with AutoCAD host's own TargetFramework attribute.

Reference csproj template — DA / Civil 3D headless
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
    <RootNamespace>$(MSBuildProjectName)</RootNamespace>
    <Nullable>enable</Nullable>
    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.WindowsDesktop.App" />
    <PackageReference Include="AutoCAD.NET.Core" Version="26.0.0" ExcludeAssets="runtime" />
    <PackageReference Include="AutoCAD.NET.Model" Version="26.0.0" ExcludeAssets="runtime" />
    <!-- Add Civil3D.NET for Civil 3D plugins -->
    <!-- <PackageReference Include="Civil3D.NET" Version="13.9.628" ExcludeAssets="runtime" /> -->
  </ItemGroup>
</Project>
Reference csproj template — Desktop-only (with UI)
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
    <RootNamespace>$(MSBuildProjectName)</RootNamespace>
    <Nullable>enable</Nullable>
    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.WindowsDesktop.App" />
    <PackageReference Include="AutoCAD.NET" Version="26.0.0" ExcludeAssets="runtime" />
  </ItemGroup>
</Project>
Plant 3D csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Library</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <PlatformTarget>x64</PlatformTarget>
    <Nullable>enable</Nullable>
    <RootNamespace>$(MSBuildProjectName)</RootNamespace>
    <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>
  </PropertyGroup>

  <ItemGroup>
    <FrameworkReference Include="Microsoft.WindowsDesktop.App" />
    <PackageReference Include="AutoCAD.NET.Core" Version="26.0.0" ExcludeAssets="runtime" />
    <PackageReference Include="AutoCAD.NET.Model" Version="26.0.0" ExcludeAssets="runtime" />
  </ItemGroup>

  <!-- Plant 3D SDK — PLANT_SDK = path to inc-x64\ folder -->
  <!-- Download: https://aps.autodesk.com/developer/overview/autocad-plant-3d-objectarx-sdk-downloads -->
  <ItemGroup>
    <Reference Include="PnIDMgd">
      <HintPath>$(PLANT_SDK)\PnIDMgd.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnPDataLinks">
      <HintPath>$(PLANT_SDK)\PnPDataLinks.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnPDataObjects">
      <HintPath>$(PLANT_SDK)\PnPDataObjects.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnPProjectManagerMgd">
      <HintPath>$(PLANT_SDK)\PnPProjectManagerMgd.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnPCommonMgd">
      <HintPath>$(PLANT_SDK)\PnPCommonMgd.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnPCommonDbxMgd">
      <HintPath>$(PLANT_SDK)\PnPCommonDbxMgd.dll</HintPath>
      <Private>false</Private>
    </Reference>
    <Reference Include="PnIdProjectPartsMgd">
      <HintPath>$(PLANT_SDK)\PnIdProjectPartsMgd.dll</HintPath>
      <Private>false</Private>
    </Reference>
  </ItemGroup>
</Project>

Set PLANT_SDK via Directory.Build.props:

<!-- Directory.Build.props (repo root) -->
<Project>
  <PropertyGroup>
    <PLANT_SDK Condition="'$(PLANT_SDK)'==''">D:\SDKS\Plant2027\inc-x64</PLANT_SDK>
  </PropertyGroup>
</Project>

Step 3 — Entry point boilerplate

Create App.cs (or verify template generated it):

using Autodesk.AutoCAD.Runtime;

[assembly: ExtensionApplication(typeof(<ProjectName>.App))]
[assembly: CommandClass(typeof(<ProjectName>.Commands))]

namespace <ProjectName>;

public class App : IExtensionApplication
{
    public void Initialize() { }
    public void Terminate() { }
}

Step 4 — Add launchSettings.json

Create Properties/launchSettings.json. Replace <ACAD_HOME> with the AutoCAD install path.

AutoCAD
{
  "profiles": {
    "<ProjectName>": { "commandName": "Project" },
    "AutoCAD2027": {
      "commandName": "Executable",
      "executablePath": "<ACAD_HOME>\\acad.exe"
    }
  }
}
Civil 3D
{
  "profiles": {
    "<ProjectName>": { "commandName": "Project" },
    "C3D2027_Metric": {
      "commandName": "Executable",
      "executablePath": "<ACAD_HOME>\\acad.exe",
      "commandLineArgs": "/ld \"<ACAD_HOME>\\AecBase.dbx\" /p \"<<C3D_Metric>>\" /product C3D /language en-US"
    },
    "C3D2027_Imperial": {
      "commandName": "Executable",
      "executablePath": "<ACAD_HOME>\\acad.exe",
      "commandLineArgs": "/ld \"<ACAD_HOME>\\AecBase.dbx\" /p \"<<C3D_Imperial>>\" /product C3D /language en-US"
    }
  }
}
Plant 3D
{
  "profiles": {
    "<ProjectName>": { "commandName": "Project" },
    "Plant3D2027": {
      "commandName": "Executable",
      "executablePath": "<ACAD_HOME>\\acad.exe",
      "commandLineArgs": "/product PLNT3D /language \"en-US\""
    }
  }
}

Step 5 — Build and load

dotnet build -c Debug

Output: bin\Debug\net10.0-windows\<ProjectName>.dll

Desktop: In AutoCAD, use NETLOAD to load the DLL (see Step 5a). accoreconsole: Use .scr script with SECURELOAD 0 then NETLOAD, or use /al (see Step 6).


Step 5a — Desktop UI testing (NETLOAD)

First-time load
  1. Launch AutoCAD (or Civil 3D / Plant 3D) via the launchSettings profile or directly
  2. At the command line: NETLOAD
  3. Browse to bin\Debug\net10.0-windows\<ProjectName>.dll
  4. Run your command (e.g., MYCOMMAND)
SECURELOAD handling

AutoCAD defaults to SECURELOAD=1 which blocks DLLs from untrusted paths. Options:

ApproachWhen to use
SECURELOAD 0 at command lineQuick one-off testing — reset per session
TRUSTEDPATHS sysvarAdd your build output folder to the trusted list (persists in registry)
TRUSTEDLOCATIONS dialogUI version of TRUSTEDPATHS — Settings > Files > Trusted Locations

To add a trusted path programmatically:

TRUSTEDPATHS

Append ;C:\your\build\output\path to the existing value.

Auto-load on startup (without ApplicationPlugins bundle)

For repeated testing, avoid typing NETLOAD every launch. Add to the Startup Suite:

  1. APPLOAD command
  2. Click "Contents..." under Startup Suite
  3. Add your DLL

Or use acad.lsp / acaddoc.lsp in the support path:

;; acaddoc.lsp — runs on every document open
(command "NETLOAD" "C:\\path\\to\\Plugin.dll")
Debugging with Visual Studio / VS Code

With launchSettings.json configured (Step 4):

  1. Set breakpoints in your code
  2. Start debugging (F5) — AutoCAD launches with the selected profile
  3. In AutoCAD: NETLOAD your DLL, then run your command
  4. Breakpoints hit in VS

For attach-to-process (when AutoCAD is already running):

  • Debug > Attach to Process > select acad.exe

Step 6 — Local testing with accoreconsole (headless)

Method A: NETLOAD via script

Create a .scr script file:

SECURELOAD
0
NETLOAD
C:\full\path\to\Plugin.dll
MYCOMMAND

Launch:

accoreconsole.exe /i "drawing.dwg" /s "test.scr" /ld "AecBase.dbx" /product C3D /language en-US
Method B: /al with .bundle (recommended)

Matches DA behavior more closely. Create a bundle folder structure:

TestBundle/
  <ProjectName>.bundle/
    PackageContents.xml
    Contents/
      <ProjectName>.dll
      <ProjectName>.deps.json

The .scr only needs the command (no SECURELOAD/NETLOAD):

MYCOMMAND

Launch:

accoreconsole.exe /i "drawing.dwg" /al "TestBundle" /s "test.scr" /isolate user1 "D:\Tmp" /ld "AecBase.dbx" /product C3D /language en-US

Rules:

  • /al points to the parent of the .bundle folder
  • Always use /isolate to prevent registry writes into your working directory
  • See autocad-api.md for full flag reference.

Step 7 — ApplicationPlugins Bundle (desktop auto-load)

For desktop deployment (not DA), place a .bundle folder in one of these paths:

PathScopeRequires admin
%APPDATA%\Autodesk\ApplicationPlugins\Current userNo
C:\Program Files\Autodesk\ApplicationPlugins\All usersYes

AutoCAD scans these on startup and loads any .bundle with a valid PackageContents.xml.

Minimal bundle for a .NET plugin
%APPDATA%\Autodesk\ApplicationPlugins\
  <ProjectName>.bundle/
    PackageContents.xml
    Contents/
      <ProjectName>.dll
      <ProjectName>.deps.json
PackageContents.xml with command registration
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage SchemaVersion="1.0" Version="1.0.0"
  ProductCode="{generate-new-guid}"
  Name="<ProjectName>"
  Description="..."
  Author="...">
  <CompanyDetails Name="..." Url="..." Email="..." />
  <RuntimeRequirements
    Platform="AutoCAD"
    SeriesMin="R26.0" SeriesMax="R26.0"
    OS="Win64" />
  <Components Description="plugin">
    <RuntimeRequirements
      SupportPath="./Contents"
      Platform="AutoCAD"
      SeriesMin="R26.0" SeriesMax="R26.0"
      OS="Win64" />
    <ComponentEntry
      AppName="<ProjectName>"
      AppType=".NET"
      Version="1.0.0"
      ModuleName="./Contents/<ProjectName>.dll"
      AppDescription="..."
      LoadOnAutoCADStartup="True"
      LoadOnCommandInvocation="False">
      <Commands GroupName="<ProjectName>_Commands">
        <Command Local="MYCOMMAND" Global="MYCOMMAND" />
      </Commands>
    </ComponentEntry>
  </Components>
</ApplicationPackage>

Key attributes:

  • Platform: AutoCAD (base), Civil3D, Plant3D, or pipe-delimited AutoCAD|Civil3D
  • SeriesMin/SeriesMax: R26.0 = 2027, R25.1 = 2026, R25.0 = 2025
  • LoadOnAutoCADStartup="True": loads DLL immediately on startup
  • LoadOnCommandInvocation="True" + LoadOnAutoCADStartup="False": deferred load (only when command is invoked)
  • SupportPath="./Contents": adds Contents folder to AutoCAD's support file search path
  • <Commands>: registers commands so AutoCAD knows which bundle to load on demand
Build script to deploy bundle locally
$BundleName = "<ProjectName>"
$BuildOut = "bin\Debug\net10.0-windows"
$BundleDest = "$env:APPDATA\Autodesk\ApplicationPlugins\$BundleName.bundle"

# Create bundle structure
New-Item "$BundleDest\Contents" -ItemType Directory -Force | Out-Null
Copy-Item "PackageContents.xml" "$BundleDest\" -Force
Copy-Item "$BuildOut\$BundleName.dll" "$BundleDest\Contents\" -Force
Copy-Item "$BuildOut\$BundleName.deps.json" "$BundleDest\Contents\" -Force

Write-Host "Deployed to: $BundleDest"

Restart AutoCAD after deploying. The bundle loads automatically.


Step 8 — DA Bundle Packaging

PackageContents.xml
<?xml version="1.0" encoding="utf-8" ?>
<ApplicationPackage SchemaVersion="1.0" Version="1.0.0"
  ProductCode="{generate-new-guid}"
  Name="<ProjectName>"
  Description="..."
  Author="...">
  <CompanyDetails Name="..." Url="..." Email="..." />
  <Components Description="plugin">
    <RuntimeRequirements
      SeriesMin="R26.0" SeriesMax="R26.0"
      Platform="AutoCAD"
      OS="Win64" />
    <ComponentEntry
      AppName="<ProjectName>"
      Version="1.0.0"
      ModuleName="./Contents/<ProjectName>.dll"
      AppDescription="..."
      LoadOnAutoCADStartup="True"
      LoadOnCommandInvocation="False" />
  </Components>
</ApplicationPackage>

SeriesMin/SeriesMax: R26.0 = AutoCAD 2027. Must match the DA engine version.

Bundle folder structure
<ProjectName>.bundle/
  PackageContents.xml
  Contents/
    <ProjectName>.dll
    <ProjectName>.deps.json
Zip correctly (CRITICAL)
# CORRECT — bundle folder is zip root
Compress-Archive -Path "$ProjectName.bundle" -DestinationPath "$ProjectName.zip"

# WRONG — puts PackageContents.xml at zip root; bundle silently not loaded
Compress-Archive -Path "$ProjectName.bundle\*" -DestinationPath "$ProjectName.zip"
DA Activity commandLine
$(engine.path)\accoreconsole.exe /i "$(args[inputFile].path)" /al "$(appbundles[<BundleName>].path)" /s "$(settings[script].path)"
  • /al loads a .bundle from a parent folder (see below for local usage)
  • /s passes the script with command invocations
Using /al locally with accoreconsole (undocumented)

/al works in desktop accoreconsole too -- it is just not in the official docs. The argument is the parent folder containing the .bundle directory:

TestFolder/
  MyPlugin.bundle/
    PackageContents.xml
    Contents/
      MyPlugin.dll

Launch:

accoreconsole.exe /i "drawing.dwg" /al "D:\TestFolder" /s "test.scr" /isolate user1 "D:\Tmp"

Rules:

  • /al points to the parent of the .bundle folder, not the bundle itself
  • Always use /isolate -- without it, /al writes registry entries into the parent folder which pollute your working directory
  • /isolate user1 <tempDir> redirects those registry writes to a temp directory
  • The .scr script does NOT need SECURELOAD 0 or NETLOAD when using /al -- the bundle is loaded automatically
DA Engine IDs (use + not .)
ProductEngine ID
AutoCAD 2027Autodesk.AutoCAD+26_0
AutoCAD 2026Autodesk.AutoCAD+25_1
AutoCAD 2025Autodesk.AutoCAD+25_0

Verified Build Output Path

After dotnet build -c Debug with the correct csproj settings:

bin\Debug\net10.0-windows\<ProjectName>.dll     ← load this
bin\Debug\net10.0-windows\<ProjectName>.deps.json
bin\Debug\net10.0-windows\<ProjectName>.pdb

If you see bin\Debug\net10.0-windows\win-x64\ subfolder, you have RuntimeIdentifier in your csproj without the proper overrides. Remove it and use PlatformTarget, or set <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>.

Comments

Markdown supported