Scaffold Skill — AutoCAD .NET Plugins
SkillCloud & infraScaffold and develop AutoCAD 2027 .NET plugins (AutoCAD, Civil 3D, Plant 3D) targeting .NET 10 / x64. Covers dotnet new templates, csproj patterns, bundle packaging, desktop NETLOAD testing, and Design Automation deployment.
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Scaffold Skill skill
What this skill tells your AI
The instructions your AI receives, as published by autodesk-platform-services/skills in skills/acad-dotnet/SKILL.md and read by ahel’s review.
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 says | Target | Template | Extra packages |
|---|---|---|---|
| "AutoCAD plugin" / "acad add-in" | AutoCAD 2027 | acad | AutoCAD.NET 26.0.0 |
| "Civil 3D plugin" / "c3d add-in" | Civil 3D 2027 | civil | Civil3D.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) | acad | Use .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
- Launch AutoCAD (or Civil 3D / Plant 3D) via the launchSettings profile or directly
- At the command line:
NETLOAD - Browse to
bin\Debug\net10.0-windows\<ProjectName>.dll - Run your command (e.g.,
MYCOMMAND)
SECURELOAD handling
AutoCAD defaults to SECURELOAD=1 which blocks DLLs from untrusted paths. Options:
| Approach | When to use |
|---|---|
SECURELOAD 0 at command line | Quick one-off testing — reset per session |
TRUSTEDPATHS sysvar | Add your build output folder to the trusted list (persists in registry) |
TRUSTEDLOCATIONS dialog | UI 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:
APPLOADcommand- Click "Contents..." under Startup Suite
- 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):
- Set breakpoints in your code
- Start debugging (F5) — AutoCAD launches with the selected profile
- In AutoCAD:
NETLOADyour DLL, then run your command - 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:
/alpoints to the parent of the.bundlefolder- Always use
/isolateto prevent registry writes into your working directory - See
autocad-api.mdfor full flag reference.
Step 7 — ApplicationPlugins Bundle (desktop auto-load)
For desktop deployment (not DA), place a .bundle folder in one of these paths:
| Path | Scope | Requires admin |
|---|---|---|
%APPDATA%\Autodesk\ApplicationPlugins\ | Current user | No |
C:\Program Files\Autodesk\ApplicationPlugins\ | All users | Yes |
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-delimitedAutoCAD|Civil3DSeriesMin/SeriesMax:R26.0= 2027,R25.1= 2026,R25.0= 2025LoadOnAutoCADStartup="True": loads DLL immediately on startupLoadOnCommandInvocation="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)"
/alloads a .bundle from a parent folder (see below for local usage)/spasses 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:
/alpoints to the parent of the.bundlefolder, not the bundle itself- Always use
/isolate-- without it,/alwrites registry entries into the parent folder which pollute your working directory /isolate user1 <tempDir>redirects those registry writes to a temp directory- The
.scrscript does NOT needSECURELOAD 0orNETLOADwhen using/al-- the bundle is loaded automatically
DA Engine IDs (use + not .)
| Product | Engine ID |
|---|---|
| AutoCAD 2027 | Autodesk.AutoCAD+26_0 |
| AutoCAD 2026 | Autodesk.AutoCAD+25_1 |
| AutoCAD 2025 | Autodesk.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>.
Signals
- GitHub stars
- 61
- Forks
- 14
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
acad-dotnet- Source
- github.com/autodesk-platform-services/skills
github.com/autodesk-platform-services/skills