
dv-solution
Dataverse solution lifecycle — create, export, import, promote across environments, and validate deployments. Use when the user wants to package customizations, deploy to another environment, or move work between dev / test / prod.
- Installs
- 215
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/microsoft/dataverse-skills --skill dv-solution- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads dv-solution automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Skill: Solution
Create, export, unpack, pack, import, and validate Dataverse solutions via PAC CLI. Includes post-import validation using the Python SDK.
Headless / restricted-egress hosts: use the raw Web API (
ExportSolution/ImportSolution) for the online steps.pac solution pack/unpackare local file operations (no auth) but need a host that can run PAC -- do them on a capable machine or CI runner. Verify egress withpython scripts/auth.py --check. Seedv-connect/references/headless-hosts.md.
Skill boundaries
| Need | Use instead |
|---|---|
| Create tables, columns, relationships, forms, views | dv-metadata |
| Create, update, or delete data records | dv-data |
| Query or read records | dv-query |
| Connect to Dataverse / set up MCP | dv-connect |
Create a New Solution
Use the Python SDK for publisher and solution record creation — not raw HTTP. Publishers and solutions are standard Dataverse tables. client.records.create() and client.records.list() handle auth, pagination, and error handling automatically, avoiding the URL encoding, header boilerplate, and GUID-parsing bugs that raw urllib calls introduce.
Step 1: Find or Create the Publisher
Every solution belongs to a publisher. The publisher's customizationprefix (e.g., contoso, sa, lit) is prepended to every custom table, column, and relationship schema name. This prefix is effectively permanent — existing components keep their prefix forever, even if you change the publisher later.
Never use the default new prefix. It provides no organizational identity, risks naming collisions, and signals the developer did not follow best practices.
Discovery flow — always run this before creating a publisher:
import os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client
# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-solution")
# 1. Query for existing non-Microsoft publishers
publishers = client.records.list(
"publisher",
filter="customizationprefix ne 'none' and uniquename ne 'MicrosoftCorporation' and uniquename ne 'Microsoftdynamic'",
select=["publisherid", "uniquename", "friendlyname", "customizationprefix"],
top=10,
)
if publishers:
# Show existing publishers and ask user which to use
print("Existing publishers in this environment:")
for p in publishers:
print(f" {p['uniquename']} (prefix: {p['customizationprefix']}_)")
# ASK THE USER: "Which publisher should this solution use?"
# Or: "Should I reuse '<name>' (prefix: <prefix>_)?"
publisher_id = publishers[0]["publisherid"] # after user confirms
else:
# No custom publisher exists — ASK THE USER for prefix
# "What publisher prefix should I use? (e.g., 'contoso', 'sa', 'lit' — 2-8 lowercase chars)"
publisher_id = client.records.create("publisher", {
"uniquename": "<publisheruniquename>",
"friendlyname": "<Publisher Display Name>",
"customizationprefix": "<prefix>", # from user input, NOT 'new'
"description": "<description>",
})
Rules:
- Always ask the user before creating a new publisher or choosing a prefix. Never hardcode a prefix.
- The prefix must match any tables already created in the solution — you cannot mix prefixes.
- One publisher can own many solutions. Reuse an existing publisher when possible.
Step 2: Create the Solution Record
Use the SDK to create the solution record (preferred over raw Web API):
import os, sys
sys.path.insert(0, os.path.join(os.getcwd(), "scripts"))
from auth import get_client
# get_client sets a plugin attribution context on the User-Agent header.
# Do not modify the context value — it is a closed schema for server-side
# telemetry (app/skill/agent). Never include secrets or PII.
client = get_client("dv-solution")
# Create the solution record
solution_id = client.records.create("solution", {
"uniquename": "<UniqueName>",
"friendlyname": "<Display Name>",
"version": "1.0.0.0",
"publisherid@odata.bind": "/publishers(<publisher_guid>)",
})
print(f"Created solution: {solution_id}")
The required fields:
Table: solution
Fields: uniquename = "<UniqueName>"
friendlyname = "<Display Name>"
version = "1.0.0.0"
publisherid = <publisher GUID from step 1>
Note: There is no
pac solution createcommand. PAC CLI handles export/import/pack/unpack, not solution record creation. Use the SDK or Web API to create the record.
Step 3: Add Components
Use pac solution add-solution-component to add tables, forms, views, and other components:
pac solution add-solution-component \
--solutionUniqueName <UniqueName> \
--component <ComponentSchemaName> \
--componentType <TypeCode> \
--environment <url>
Note: PAC CLI uses camelCase args here (
--solutionUniqueName,--componentType), not kebab-case.
Common component type codes:
| Type Code | Component |
|---|---|
| 1 | Entity (Table) |
| 2 | Attribute (Column) |
| 26 | View |
| 60 | Form |
| 61 | Web Resource |
| 300 | Canvas App |
| 371 | Connector |
Repeat the command for each component you need to add.
Alternative: Auto-add via MSCRM.SolutionName Header
When creating metadata via the Web API, include the MSCRM.SolutionName header to auto-add components to the solution:
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"MSCRM.SolutionName": "<UniqueName>"
}
Important: After using this approach, verify components were added by querying the solutioncomponent table with the SDK (pac solution list-components is not available in current PAC):
sol = client.records.list("solution",
filter="uniquename eq '<UniqueName>'", select=["solutionid"], top=1).first()
if sol is not None:
components = client.records.list("solutioncomponent",
filter=f"_solutionid_value eq {sol['solutionid']}",
select=["componenttype", "objectid"])
print(f"{len(components)} components in the solution")
If the header was misspelled or the solution doesn't exist, components will be created in the default solution instead — silently. Always verify.
Find the Solution Name
Before exporting, confirm the exact unique name:
pac solution list --environment <url>
The UniqueName column is what you pass to other commands. Display names have spaces; unique names do not.
Pull: Export + Unpack
Confirm the target environment before exporting or importing. Run
pac auth list+pac org who, show the output to the user, and confirm it matches the intended environment. Developers work across multiple environments — do not assume.
Export the solution as unmanaged (source of truth):
pac solution export \
--name <UniqueName> \
--path ./solutions/<UniqueName>.zip \
--managed false \
--environment <url>
Unpack into editable source files:
pac solution unpack \
--zipfile ./solutions/<UniqueName>.zip \
--folder ./solutions/<UniqueName> \
--packagetype Unmanaged
Windows file-lock race. Run export and unpack as separate commands (as above); chaining them immediately can hit a transient ZIP file-lock right after export. If
unpackfails with a lock / "in use" error, retry after a moment, and verify the unpacked folder has the expected components before deleting the zip.
Delete the zip — the unpacked folder is the source:
rm ./solutions/<UniqueName>.zip
Commit:
git add ./solutions/<UniqueName>
git commit -m "chore: pull <UniqueName> baseline"
git push
Push: Pack + Import
Pack the source files back into a zip:
pac solution pack \
--zipfile ./solutions/<UniqueName>.zip \
--folder ./solutions/<UniqueName> \
--packagetype Unmanaged
Import (async recommended for large solutions):
pac solution import \
--path ./solutions/<UniqueName>.zip \
--environment <url> \
--async \
--activate-plugins
Poll Import Status
After async import, check the job:
pac solution list --environment <url>
Post-Import Validation
After importing a solution, verify that components are live. Use the Python SDK to check directly — no external scripts needed.
Check a table exists
info = client.tables.get("<logical_name>")
if info:
print(f"[PASS] Table '{info.logical_name}' exists")
else:
print(f"[FAIL] Table '<logical_name>' not found")
Check a form is published
forms = client.records.list(
"systemform",
filter="objecttypecode eq '<entity>' and type eq <form_type_code>",
select=["name", "formid"],
top=5,
)
# Form type codes: 2 = main, 7 = quick create
Check a view exists
views = client.records.list(
"savedquery",
filter="returnedtypecode eq '<entity>'",
select=["name", "savedqueryid", "statuscode"],
top=10,
)
Check a user's role assignment (N:N $expand)
records.list passes $expand straight through, so read the N:N navigation property directly with the SDK:
users = list(client.records.list(
"systemuser",
filter="internalemailaddress eq '<email>'", # fallback: domainname eq '<upn>'
select=["fullname"],
expand=["systemuserroles_association($select=name)"],
top=1,
))
roles = [r["name"] for r in users[0].get("systemuserroles_association", [])] if users else []
Alternatively, the managed Dataverse CLI escape hatch (dataverse api request — not urllib), or FetchXML with a link-entity:
dataverse api request --target dataverse --method GET \
--path "/api/data/v9.2/systemusers?%24filter=internalemailaddress eq '<email>'&%24select=fullname&%24expand=systemuserroles_association(%24select=name)&%24top=1" \
--environment <DATAVERSE_URL> \
--context "app=dataverse-skills/<ver>;skill=dv-solution;agent=<agent>"
The response value[0].systemuserroles_association is the list of assigned roles (each with name).
Check import errors
jobs = client.records.list(
"importjob",
select=["importjobid", "solutionname", "startedon", "completedon", "progress"],
orderby=["startedon desc"],
top=5,
)
For detailed error history, also query msdyn_solutionhistory:
history = client.records.list(
"msdyn_solutionhistory",
filter="msdyn_status eq 1", # 1 = failed
select=["msdyn_name", "msdyn_starttime", "msdyn_exceptionmessage"],
orderby=["msdyn_starttime desc"],
top=5,
)
Validation error reference
| Error | Cause | Fix |
|---|---|---|
| Table not found after import | Component not in solution | Add via pac solution add-solution-component |
| Form check fails immediately | Publishing is async | Wait 30 seconds and retry |
| Role not assigned | User not provisioned | Assign the role via pac admin assign-user or the Power Platform Admin Center |
| Import job at 0% | Import still running | Poll again in 60 seconds |
Notes
- Always use
--managed false/--packagetype Unmanagedfor the development solution. Managed packages are for deployment to downstream environments (test, prod). --activate-pluginsensures any registered plugins in the solution are activated on import.- If you see "solution already exists" errors, use
--import-mode ForceUpgradeto overwrite. - Large solutions (Sales, Customer Service) can take 10–20 minutes to import. Be patient and poll rather than re-importing.
- All validation queries above require auth. Use
scripts/auth.pyfor credential/token acquisition. Seedv-queryfor SDK query patterns anddv-datafor write patterns.
FAQ
What does the dv-solution skill do?
Dataverse solution lifecycle — create, export, import, promote across environments, and validate deployments. Use when the user wants to package customizations, deploy to another environment, or move work between dev / test / prod.
How do I install dv-solution?
Run npx skills add https://github.com/microsoft/dataverse-skills --skill dv-solution in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/dv-solution/ (personal) or .claude/skills/dv-solution/ (project).
Which AI agents can use dv-solution?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is dv-solution safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains dv-solution?
It is published by microsoft in microsoft/dataverse-skills, and it is an official skill from the maker of the technology it covers. It has 215 recorded installs.
More from microsoft/dataverse-skills
dv-connect
microsoft/dataverse-skills
Open the skill to read its SKILL.md instructions.
dv-metadata
microsoft/dataverse-skills
Dataverse schema authoring and inspection — tables, columns, relationships, forms, and views. Use when the user wants to define, evolve, or inspect the data model — add a column, create a table, set up a lookup, customize a form, build a view, or list existing columns and relationships.
dv-overview
microsoft/dataverse-skills
Foundational cross-cutting context for Dataverse / Power Platform work — scope and the skill map, the tool-capability reference, the safety rules, and the safe change lifecycle. Use when the user mentions Dataverse, Dynamics 365, Power Platform, CRM, or ERP; load this first for orientation. Specialist skills self-route via their own frontmatter triggers. Finance and Operations / F&O business-data requests also require this skill first, then dv-query for reads.
dv-query
microsoft/dataverse-skills
Bulk reads, multi-page iteration, and analytics over Dataverse data. Use when the user wants to read, list, filter, aggregate, group, join, or analyze records — including pandas DataFrame workflows and notebook exploration. Also covers ERP (Finance and Operations / F&O) business-data reads and runtime entity, schema, or action discovery; load dv-overview first, then this skill.
dv-data
microsoft/dataverse-skills
Open the skill to read its SKILL.md instructions.
dv-security
microsoft/dataverse-skills
Security-role assignment, user access, application users, business units, and admin self-elevation in Dataverse environments. Use when the user wants to give someone access, grant a role, become an admin, or add a service principal.
Popular devops & cloud skills
microsoft-foundry
microsoft/azure-skills
Build, deploy, evaluate, optimize, fine-tune, and manage Microsoft Foundry agents, models, and resources end to end. USE FOR: foundry, azd ai agent, azd provision/deploy, hosted agent scaffold/develop/run/deploy/troubleshoot, prompt agent create, managed harness agent create, GitHub Copilot harness agent, create agent, update agent, add tool to agent, invoke agent, agent insights, evaluate agent, batch eval, continuous eval, continuous monitoring, agent CI/CD, optimize prompt, improve prompt, optimize agent instructions, Agent Optimizer scaffold, dataset curation from traces, deploy model, model fine-tuning (SFT/DPO/RFT), Foundry project, RBAC, role assignment, permissions, quota, capacity, region, deployment failure, AI Services, create Foundry resource, knowledge index, customize deployment, onboard, availability, training-data, grader, distillation, large file upload. DO NOT USE FOR: Azure Functions, App Service, general Azure deploy (use azure-deploy), general Azure prep (use azure
azure-diagnostics
microsoft/azure-skills
Debug Azure production issues on Azure using AppLens, Azure Monitor, resource health, and safe triage. WHEN: debug production issues, troubleshoot app service, app service high CPU, app service deployment failure, troubleshoot container apps, container app 503 or target port mismatch, troubleshoot functions, function telemetry missing or stopped after a config/connection-string change, troubleshoot AKS, VM RDP, Linux SSH, VM black screen, can't connect to VM, reset VM password, NSG or firewall blocking, kubectl cannot connect, kube-system/CoreDNS failures, pod pending, crashloop, node not ready, upgrade failures, analyze logs, KQL, insights, image pull failures, cold start issues, health probe failures, resource health, root cause of errors, troubleshoot event hubs, troubleshoot service bus, messaging SDK error, AMQP connection failure, message lock lost, lock renewal during long-running processing, service bus dead letter.
azure-prepare
microsoft/azure-skills
Prepare azd-based Azure projects for deployment: generates azure.yaml, infrastructure (Bicep/Terraform), and Dockerfiles for the Azure Developer CLI (azd) workflow. USE ONLY when the user explicitly wants to use azd as the deployment tool, or the project already has an azure.yaml file. DO NOT USE FOR: non-azd deployments, Python App Service code-only deploys (use python-appservice-deploy), or cross-cloud migration (use azure-cloud-migrate). WHEN: prepare app for azd, create azure.yaml, set up azd infrastructure, modernize app for Azure with azd, deploy with azd, function app, timer trigger, service bus trigger, event-driven function, managed identity, generate Bicep, generate Terraform, create and deploy to Azure.
azure-ai
microsoft/azure-skills
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
azure-deploy
microsoft/azure-skills
Execute Azure deployments for ALREADY-PREPARED applications that have existing .azure/deployment-plan.md and infrastructure files. DO NOT use this skill when the user asks to CREATE a new application — use azure-prepare instead. This skill runs azd up, azd deploy, terraform apply, and az deployment commands with built-in error recovery. Requires .azure/deployment-plan.md from azure-prepare and validated status from azure-validate. WHEN: "run azd up", "run azd deploy", "execute deployment", "push to production", "push to cloud", "go live", "ship it", "bicep deploy", "terraform apply", "publish to Azure", "launch on Azure". DO NOT USE WHEN: "create and deploy", "build and deploy", "create a new app", "set up infrastructure", "create and deploy to Azure using Terraform" — use azure-prepare for these.
azure-validate
microsoft/azure-skills
Pre-deployment validation for Azure readiness. Run deep checks on configuration, infrastructure (Bicep or Terraform), RBAC role assignments, managed identity permissions, and prerequisites before deploying. WHEN: validate my app, check deployment readiness, run preflight checks, verify configuration, check if ready to deploy, validate azure.yaml, validate Bicep, test before deploying, troubleshoot deployment errors, validate Azure Functions, validate function app, validate serverless deployment, verify RBAC roles, check role assignments, review managed identity permissions, what-if analysis, validate Container Apps deployment.