[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M711HT2C9R6HZ77PVWYFQ41E":3,"skill-same:01M711HT2C9R6HZ77PVWYFQ41E":75},{"skillNo":4,"name":5,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":28,"linkOnly":29,"markdownContent":30,"markdownBody":30,"frontMatter":31,"refName":32,"commitSha":33,"skillDirectory":34,"forksCount":35,"repositoryHtmlUrl":36,"repositoryHomepageUrl":6,"ownerHtmlUrl":37,"ownerBlogUrl":38,"ownerDescription":39,"updatedAt":40,"install":41,"resources":54},"01M711HT2C9R6HZ77PVWYFQ41E","Airtable to Power Platform Migration",null,"microsoft\u002Fpower-cat-skills","microsoft","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F6154722?v=4","01M698VYDXZ6JW5WH3CRV650R8","Microsoft","01M711HNR06SENTW4XRAD4QG81",70,"MIT","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,5],"power platform","power","migration","airtable","platform","2026-11-10 10:12:30",false,"# Airtable to Microsoft App Modernization Skill\n\nThis skill migrates an Airtable app into a Microsoft data platform target and then lets the user choose the target app experience: Code App, Canvas App, both, or plan-only. It supports Dataverse tables and SharePoint Lists as data targets. It is designed for Claude\u002FGitHub Copilot-style agents with shell, filesystem, Dataverse MCP, Microsoft Graph\u002FSharePoint MCP or PnP PowerShell, and optional app-generation tooling access.\n\nThe skill owns the full flow:\n\n1. Connect to Airtable through a local prompt.\n2. Export schema and data.\n3. Analyze Airtable tables, fields, relationships, choices, AI fields, identity fields, and records.\n4. Ask whether the user wants Dataverse tables, SharePoint Lists, both, or plan-only.\n5. Produce and review the selected target migration plan.\n6. For Dataverse: connect through Dataverse MCP, resolve solution\u002Fprefix, create schema, validate, and import data.\n7. For SharePoint: connect through Graph\u002FSharePoint MCP or PnP PowerShell interactive auth, resolve site, create lists\u002Fcolumns, validate, and import data.\n8. Ask whether the user wants a Code App, Canvas App, both, or plan-only.\n9. Generate the selected app experience from the migrated Microsoft data platform target.\n\n## Critical rules\n\n- Never ask the user to paste Airtable tokens, Dataverse tokens, passwords, or secrets into chat.\n- Airtable token input must happen through a local terminal prompt using `Read-Host -AsSecureString`.\n- Never print token length, prefix, suffix, masked token metadata, or token-derived values.\n- Dataverse sign-in must happen through Dataverse MCP interactive auth, not by pasting tokens.\n- SharePoint sign-in must happen through Graph\u002FSharePoint MCP interactive auth, PnP PowerShell `Connect-PnPOnline -Interactive`, or another approved local auth tool, not by pasting tokens.\n- Do not create Dataverse or SharePoint objects until the user approves the reviewed target plan.\n- Do not import data until target schema\u002Flist creation is verified.\n- Do not populate `systemuser` lookups or change record `Owner` until identity mapping is separately approved.\n- Never create Dataverse `systemuser` rows.\n- All Dataverse metadata creation must happen inside the selected solution.\n- If the target solution already exists, derive the prefix from the solution publisher. Do not infer prefix from the solution name.\n- If the target solution does not exist, ask whether to create it and which publisher\u002Fprefix to use.\n- For SharePoint targets, ask for\u002Fresolve the target site URL and create\u002Freuse lists only after explicit approval.\n- SharePoint Person\u002FGroup columns can be used for user fields, but preserve source name\u002Femail text so unresolved users do not block migration.\n- UX and automation conversion are optional post-migration phases. Treat them as reviewable scaffolds\u002Fdrafts, not guaranteed pixel-perfect or behavior-complete clones.\n- Reuse the established Dataverse or SharePoint target context for app data sources and Flow\u002FPower Automate environment selection when available.\n- In addition to machine-readable JSON artifacts, generate user-friendly DOCX plans\u002Freports when document-generation tooling is available.\n\n## Expected agent capabilities\n\nThe agent should have:\n\n- shell access\n- filesystem access\n- internet access for Airtable API calls\n- Dataverse MCP tools or a Dataverse MCP server configured in the agent environment\n- Microsoft Graph\u002FSharePoint MCP tools, an equivalent SharePoint-capable MCP server, or PnP PowerShell when SharePoint Lists are selected\n\nIf Dataverse MCP is unavailable, stop at the Dataverse MCP preflight and tell the user what is missing. Do not improvise another auth path unless the user explicitly asks.\nIf SharePoint\u002FGraph MCP is unavailable and SharePoint Lists are selected, offer PnP PowerShell interactive as the supported fallback. If neither SharePoint MCP nor PnP PowerShell is available, stop and tell the user what is missing.\n\n## Phase 0: Start\n\nWhen invoked, say:\n\n> We will start in assessment mode. I will export Airtable locally, analyze the schema\u002Fdata, ask whether you want Dataverse tables, SharePoint Lists, both, or plan-only, then connect to the selected Microsoft target through MCP. I will not create target objects or import data until you approve the target environment\u002Fsite, schema\u002Flist plan, and object list.\n\nThen create a fresh run by default.\n\n### Fresh-run rule\n\nEvery invocation starts a new timestamped run folder unless the user explicitly says they want to resume a prior run.\n\nDefault behavior:\n\n```text\nairtable-migration-work\u002F\n  runs\u002F\n    \u003CyyyyMMdd-HHmmss>\u002F\n      README.md\n      scripts\u002F\n      exports\u002F\n      analysis\u002F\n      runbooks\u002F\n      reports\u002F\n      flows\u002F\n      apps\u002F\n        code-app\u002F\n        canvas-app\u002F\n      logs\u002F\n      validation\u002F\n      temp\u002F\n```\n\nRules:\n\n- The timestamped run folder is the single container for the migration. All artifacts for that migration must land under that folder.\n- Do not silently reuse prior exports, plans, approvals, Dataverse creation results, or import reports.\n- Do not say a prior migration is already done unless the user explicitly selected resume.\n- Treat prior runs as historical reference only.\n- A fresh run must create a new export, new assessment, new schema plan, and new approval gates.\n- Do not write generated apps, flow drafts, runbooks, reports, logs, screenshots, or temporary files outside the active run folder unless the user explicitly asks for a different output path.\n- If existing Dataverse objects are detected during creation, handle them with idempotency\u002Fschema-drift checks, not by assuming the prior skill run completed correctly.\n\nAsk only if a prior run is detected:\n\n```text\nPrior migration runs were found. Start fresh or resume one?\n```\n\nRecommended\u002Fdefault answer: Start fresh.\n\n## Phase 1: Generate Airtable export scripts\n\nCreate or use the current fresh run folder:\n\n```text\nairtable-migration-work\u002F\n  runs\u002F\n    \u003Ctimestamp>\u002F\n      README.md\n      scripts\u002F\n      exports\u002F\n      analysis\u002F\n      runbooks\u002F\n      reports\u002F\n      flows\u002F\n      apps\u002F\n        code-app\u002F\n        canvas-app\u002F\n      logs\u002F\n      validation\u002F\n      temp\u002F\n```\n\nSet an internal `ACTIVE_RUN_FOLDER` variable\u002Fpath and use it for every output in the run.\n\nGenerate:\n\n```text\n\u003CACTIVE_RUN_FOLDER>\u002Fscripts\u002Fstart-airtable-export.ps1\n\u003CACTIVE_RUN_FOLDER>\u002Fscripts\u002Fexport-airtable.ps1\n```\n\n### `scripts\u002Fstart-airtable-export.ps1`\n\n```powershell\n$ErrorActionPreference = \"Stop\"\n\n$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path\n$exporterPath = Join-Path $scriptDir \"export-airtable.ps1\"\n\nif (-not (Test-Path $exporterPath)) {\n    throw \"Could not find exporter script at $exporterPath\"\n}\n\n$secureToken = Read-Host \"Enter Airtable token\" -AsSecureString\n$env:AIRTABLE_BASE_ID = Read-Host \"Enter Airtable base ID\"\n\n$tokenPtr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureToken)\ntry {\n    $env:AIRTABLE_TOKEN = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($tokenPtr)\n}\nfinally {\n    [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($tokenPtr)\n}\n\nif ([string]::IsNullOrWhiteSpace($env:AIRTABLE_TOKEN)) { throw \"Airtable token is required.\" }\nif ([string]::IsNullOrWhiteSpace($env:AIRTABLE_BASE_ID)) { throw \"Airtable base ID is required.\" }\n\nWrite-Host \"\"\nWrite-Host \"Airtable token captured securely.\"\nWrite-Host \"Base ID: $env:AIRTABLE_BASE_ID\"\nWrite-Host \"\"\n\n& $exporterPath\n```\n\n### `scripts\u002Fexport-airtable.ps1`\n\n```powershell\n$ErrorActionPreference = \"Stop\"\n\nif ([string]::IsNullOrWhiteSpace($env:AIRTABLE_TOKEN)) { throw \"AIRTABLE_TOKEN is not set. Run start-airtable-export.ps1 first in this same PowerShell window.\" }\nif ([string]::IsNullOrWhiteSpace($env:AIRTABLE_BASE_ID)) { throw \"AIRTABLE_BASE_ID is not set. Run start-airtable-export.ps1 first in this same PowerShell window.\" }\n\n$baseId = $env:AIRTABLE_BASE_ID\n$timestamp = Get-Date -Format \"yyyyMMdd-HHmmss\"\n$exportRoot = Join-Path (Get-Location) \"..\\exports\\airtable-export-$baseId-$timestamp\"\n$exportRoot = [System.IO.Path]::GetFullPath($exportRoot)\n\n$schemaDir = Join-Path $exportRoot \"schema\"\n$dataDir = Join-Path $exportRoot \"data\"\n$attachmentsDir = Join-Path $exportRoot \"attachments\"\n$interfacesDir = Join-Path $exportRoot \"interfaces\"\n$automationsDir = Join-Path $exportRoot \"automations\"\n$permissionsDir = Join-Path $exportRoot \"permissions\"\n$identityDir = Join-Path $exportRoot \"identity\"\n$analysisDir = Join-Path $exportRoot \"analysis\"\n\nNew-Item -ItemType Directory -Force -Path $schemaDir, $dataDir, $attachmentsDir, $interfacesDir, $automationsDir, $permissionsDir, $identityDir, $analysisDir | Out-Null\nNew-Item -ItemType Directory -Force -Path (Join-Path $interfacesDir \"screenshots\") | Out-Null\n\n$headers = @{ Authorization = \"Bearer $env:AIRTABLE_TOKEN\" }\n\nfunction ConvertTo-SafeFileName {\n    param([string]$Name)\n    $invalid = [System.IO.Path]::GetInvalidFileNameChars()\n    $safe = $Name\n    foreach ($char in $invalid) { $safe = $safe.Replace($char, \"_\") }\n    return $safe\n}\n\nfunction Invoke-AirtableGet {\n    param([string]$Uri)\n    return Invoke-RestMethod -Method Get -Uri $Uri -Headers $headers\n}\n\nfunction Write-JsonArray {\n    param([System.Collections.IEnumerable]$Items, [string]$Path)\n    $array = @($Items)\n    if ($array.Count -eq 0) {\n        \"[]\" | Set-Content -Encoding UTF8 $Path\n        return\n    }\n    $array | ConvertTo-Json -Depth 100 | Set-Content -Encoding UTF8 $Path\n}\n\ntry {\n    Write-Host \"Exporting Airtable base metadata...\"\n    $metadataUri = \"https:\u002F\u002Fapi.airtable.com\u002Fv0\u002Fmeta\u002Fbases\u002F$baseId\u002Ftables\"\n    $metadata = Invoke-AirtableGet -Uri $metadataUri\n    $metadata | ConvertTo-Json -Depth 100 | Set-Content -Encoding UTF8 (Join-Path $schemaDir \"base.json\")\n    Write-JsonArray -Items @($metadata.tables) -Path (Join-Path $schemaDir \"tables.json\")\n\n    $views = foreach ($table in @($metadata.tables)) {\n        foreach ($view in @($table.views)) {\n            [pscustomobject]@{\n                tableId = $table.id\n                tableName = $table.name\n                viewId = $view.id\n                viewName = $view.name\n                type = $view.type\n            }\n        }\n    }\n    Write-JsonArray -Items @($views) -Path (Join-Path $schemaDir \"views.json\")\n\n    $attachmentManifest = New-Object System.Collections.Generic.List[object]\n    $tableSummaries = New-Object System.Collections.Generic.List[object]\n\n    foreach ($table in @($metadata.tables)) {\n        $safeTableName = ConvertTo-SafeFileName -Name $table.name\n        $records = New-Object System.Collections.Generic.List[object]\n        $offset = $null\n        Write-Host \"Exporting records from table: $($table.name)\"\n\n        do {\n            $recordsUri = \"https:\u002F\u002Fapi.airtable.com\u002Fv0\u002F$baseId\u002F$($table.id)?pageSize=100\"\n            if (-not [string]::IsNullOrWhiteSpace($offset)) {\n                $recordsUri = \"$recordsUri&offset=$([System.Uri]::EscapeDataString($offset))\"\n            }\n\n            $page = Invoke-AirtableGet -Uri $recordsUri\n            foreach ($record in @($page.records)) {\n                $records.Add($record)\n\n                foreach ($field in @($table.fields)) {\n                    if ($field.type -eq \"multipleAttachments\" -and $record.fields.PSObject.Properties.Name -contains $field.name) {\n                        foreach ($attachment in @($record.fields.($field.name))) {\n                            $attachmentManifest.Add([pscustomobject]@{\n                                tableId = $table.id\n                                tableName = $table.name\n                                fieldId = $field.id\n                                fieldName = $field.name\n                                recordId = $record.id\n                                attachmentId = $attachment.id\n                                fileName = $attachment.filename\n                                type = $attachment.type\n                                size = $attachment.size\n                                url = $attachment.url\n                            })\n                        }\n                    }\n                }\n            }\n            $offset = $page.offset\n        } while (-not [string]::IsNullOrWhiteSpace($offset))\n\n        $recordFile = Join-Path $dataDir \"$($table.id)-$safeTableName.records.json\"\n        Write-JsonArray -Items $records.ToArray() -Path $recordFile\n\n        $tableSummaries.Add([pscustomobject]@{\n            id = $table.id\n            name = $table.name\n            fieldCount = @($table.fields).Count\n            viewCount = @($table.views).Count\n            recordCount = $records.Count\n            recordFile = Split-Path -Leaf $recordFile\n        })\n    }\n\n    Write-JsonArray -Items $attachmentManifest.ToArray() -Path (Join-Path $attachmentsDir \"manifest.json\")\n\n    $summaryTables = $tableSummaries.ToArray()\n    $summary = [pscustomobject]@{\n        exportedAt = (Get-Date).ToString(\"o\")\n        baseId = $baseId\n        tableCount = @($metadata.tables).Count\n        tables = $summaryTables\n        attachmentCount = $attachmentManifest.Count\n        notes = @(\n            \"Airtable Interface Designer pages are not included in the Airtable API export.\",\n            \"Add screenshots or recordings under interfaces\\\\screenshots before Code App UX reconstruction.\",\n            \"Add automation screenshots, scripts, and notes under automations when available.\",\n            \"Add identity mapping input under identity\\\\identity-mapping-input.csv if AAD object IDs or UPN mappings are available.\",\n            \"Airtable AI fields are migratable as multiline text; prompt regeneration is a post-migration enhancement.\"\n        )\n    }\n    $summary | ConvertTo-Json -Depth 100 | Set-Content -Encoding UTF8 (Join-Path $analysisDir \"source-summary.json\")\n\n    $identityReadme = @\"\nOptional identity mapping input:\n\nCreate identity-mapping-input.csv here if you have Entra\u002FAAD identifiers.\nRecommended columns:\nsource_table,source_record_id,source_name,source_email,source_upn,azureactivedirectoryobjectid\n\nMatch priority:\n1. azureactivedirectoryobjectid\n2. customer-provided object ID mapping\n3. UPN\u002Fdomainname\n4. internalemailaddress\n5. display name only for manual review\n\"@\n    $identityReadme | Set-Content -Encoding UTF8 (Join-Path $identityDir \"README.txt\")\n\n    $manifest = [pscustomobject]@{\n        packageType = \"airtable-codeapp-migration-export\"\n        version = \"1.0\"\n        exportedAt = (Get-Date).ToString(\"o\")\n        baseId = $baseId\n        folders = @{\n            schema = \"schema\"\n            data = \"data\"\n            attachments = \"attachments\"\n            interfaces = \"interfaces\"\n            automations = \"automations\"\n            permissions = \"permissions\"\n            identity = \"identity\"\n            analysis = \"analysis\"\n        }\n    }\n    $manifest | ConvertTo-Json -Depth 100 | Set-Content -Encoding UTF8 (Join-Path $exportRoot \"manifest.json\")\n\n    Write-Host \"\"\n    Write-Host \"Airtable export complete.\"\n    Write-Host \"Export folder: $exportRoot\"\n}\nfinally {\n    Remove-Item Env:\\AIRTABLE_TOKEN -ErrorAction SilentlyContinue\n    Write-Host \"AIRTABLE_TOKEN has been cleared from this PowerShell session.\"\n}\n```\n\nTell the user to run:\n\n```powershell\ncd \"\u003Cworking-folder>\\scripts\"\nSet-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass\n.\\start-airtable-export.ps1\n```\n\n## Phase 2: Analyze export\n\nFind the newest `exports\u002Fairtable-export-*` folder.\n\nRead:\n\n```text\nmanifest.json\nanalysis\u002Fsource-summary.json\nschema\u002Ftables.json\nschema\u002Fviews.json\ndata\u002F*.records.json\nattachments\u002Fmanifest.json\nidentity\u002Fidentity-mapping-input.csv, if present\n```\n\nCreate:\n\n```text\nanalysis\u002Fmigration-assessment.json\nanalysis\u002Fai-field-mapping.json\nidentity\u002Fidentity-mapping-proposal.json\nanalysis\u002Ftarget-platform-recommendation.json\nanalysis\u002Ftarget-details.json\nanalysis\u002Fdataverse-schema-plan.json\nanalysis\u002Fdataverse-creation-runbook.json\nanalysis\u002Fdataverse-target-context.json, if Dataverse is selected\nanalysis\u002Fsharepoint-list-plan.json, if SharePoint is selected or recommended\nanalysis\u002Fsharepoint-import-plan.json, if SharePoint is selected or recommended\nanalysis\u002Fsharepoint-target-context.json, if SharePoint is selected\nreports\u002FData-Migration-Plan.docx, if DOCX tooling is available\n```\n\n## Phase 3: Target platform choice\n\nAfter Airtable export analysis, ask:\n\n> Where do you want to migrate the Airtable data?\n\nOffer choices:\n\n1. Dataverse tables.\n2. SharePoint Lists.\n3. Both.\n4. Plan only.\n\nBefore the user chooses, generate and show `analysis\u002Ftarget-platform-recommendation.json`.\n\nRecommendation guidance:\n\n```text\nRecommend Dataverse when:\n  - relationships are important\n  - row-level security, ownership, teams, or roles matter\n  - data volume or lifecycle complexity is high\n  - app logic needs robust APIs\u002Fplugins\u002Fsolutions\n  - Code App or enterprise Canvas App is likely\n\nRecommend SharePoint Lists when:\n  - data is simple\u002Flist-like\n  - relationships are shallow\n  - the customer wants lightweight lists\u002Fforms quickly\n  - SharePoint site\u002Flist ownership is preferred\n  - Canvas App or simple Power Automate over lists is enough\n\nRecommend Both when:\n  - Dataverse is the system of record\n  - SharePoint Lists are needed for lightweight team collaboration or read-only operational views\n\nRecommend Plan only when:\n  - target auth\u002Ftooling is unavailable\n  - relationship\u002Fsecurity complexity needs review\n  - the user is still deciding between targets\n```\n\nDo not create either target until the user approves the selected target plan.\n\n## Phase 4: Target details intake\n\nRun this immediately after the user selects Dataverse, SharePoint Lists, Both, or Plan only. This is a logical first step before target-specific planning because the environment\u002Fsite\u002Fsolution\u002Flist container affects naming, prefix, permissions, available connectors, and whether artifacts can be created.\n\n### If Dataverse is selected\n\nAsk for:\n\n- Target Dataverse environment URL.\n- Whether to use an existing solution or create a new solution.\n- Existing\u002Fnew solution display name.\n- Existing\u002Fnew solution unique name, if known.\n- Publisher name\u002Fprefix only if a new solution must be created or multiple publishers are available.\n- Whether optional `systemuser` lookup columns should be created now but left unpopulated.\n- Whether record `Owner` should remain unchanged\u002Fdefault. Default: yes.\n\nThen, through Dataverse MCP preflight, validate:\n\n- signed-in user\n- target environment URL\n- metadata read permission\n- solution exists or can be created\n- publisher and customization prefix\n- create permission, if creation is requested\n\nDo not derive the prefix from the solution name. If the solution exists, derive prefix from the solution publisher. If creating a new solution, derive prefix from the selected publisher.\n\nWrite\u002Fupdate:\n\n```text\nanalysis\u002Ftarget-details.json\nanalysis\u002Fdataverse-target-context.json\n```\n\n### If SharePoint Lists are selected\n\nAsk for:\n\n- Target SharePoint site URL.\n- SharePoint execution path:\n  - SharePoint\u002FGraph MCP\n  - PnP PowerShell interactive\n  - Plan only\n- Whether to create new lists or reuse existing lists.\n- Preferred list naming convention or list name prefix\u002Fsuffix.\n- Whether each Airtable table should become a separate list. Default: yes.\n- Whether simple linked-record fields should become SharePoint lookup columns. Default: yes.\n- How to handle many-to-many relationships:\n  - junction list\n  - multi-lookup\n  - text fallback\n  - recommend Dataverse instead\n- Whether person-like fields should create SharePoint Person\u002FGroup columns. Default: yes, with source text\u002Femail preserved.\n- Whether unresolved users should leave Person\u002FGroup blank and keep source text\u002Femail. Default: yes.\n- Attachment strategy:\n  - list attachments\n  - document library\n  - metadata only\n\nThen, through the selected SharePoint execution path, validate:\n\n- signed-in user\n- target site exists\n- list read permission\n- list creation\u002Fupdate permission\n- user resolution capability for Person\u002FGroup fields\n- lookup column feasibility\n\nWrite\u002Fupdate:\n\n```text\nanalysis\u002Ftarget-details.json\nanalysis\u002Fsharepoint-target-context.json\n```\n\n### If Both is selected\n\nCollect and validate both Dataverse and SharePoint details. Ask which target is the system of record:\n\n```text\n1. Dataverse is system of record; SharePoint is collaboration\u002Fread-only\u002Foperational view.\n2. SharePoint is system of record; Dataverse is optional advanced app target.\n3. Both are independent outputs from Airtable.\n```\n\nDefault recommendation: Dataverse as system of record, SharePoint as collaboration\u002Fread-only\u002Foperational view.\n\n### If Plan only is selected\n\nAsk for intended target details if known, but do not require auth. Mark unknown details as assumptions in the plan.\n\n## Phase 5: AI field mapping\n\nFor Airtable `aiText` fields or fields marked `(AI)`:\n\n- Create Dataverse column as multiline text.\n- Migrate current generated value when present.\n- Mark as `aiDerived: true`.\n- Classify as `migratable_with_gap`.\n- Extract prompt text and referenced field names.\n- Do not block migration if values are null, empty, or stale.\n- Recommend manual recreation as Copilot prompt, Power Automate AI step, plugin\u002Faction, or app-side AI command only if ongoing generation is needed.\n\n## Phase 6: Identity mapping\n\nUse a custom person table plus optional `systemuser` lookup:\n\n```text\nTeam Member \u002F Employee custom table\n  Mapped Dataverse User -> systemuser, optional\n\nWork item \u002F ticket table\n  Assigned Team Member -> custom person table\n  Assigned System User -> systemuser, optional\n  Owner -> unchanged unless row-level security is approved\n```\n\nMatch priority:\n\n1. `azureactivedirectoryobjectid`\n2. customer-provided object ID mapping file\n3. UPN \u002F `domainname`\n4. `internalemailaddress`\n5. display name only for manual review\n\nClassify each source person:\n\n- `active_match`\n- `disabled_match`\n- `multiple_match`\n- `no_match`\n- `missing_identifier`\n- `manual_review`\n\nDo not populate optional Dataverse `systemuser` lookups or SharePoint Person\u002FGroup fields until the user approves identity mapping.\n\n## Phase 7: SharePoint Lists planning branch\n\nRun this if the user selected SharePoint Lists or Both.\n\nGenerate:\n\n```text\nanalysis\u002Fsharepoint-list-plan.json\nanalysis\u002Fsharepoint-import-plan.json\nreports\u002FSharePoint-Migration-Plan.docx, if DOCX tooling is available\n```\n\nDefault Airtable to SharePoint mapping:\n\n```text\nAirtable table -> SharePoint list\nsingleLineText -> Single line of text\nmultilineText -> Multiple lines of text\nnumber -> Number\ndate\u002FdateTime -> Date and time\ncheckbox -> Yes\u002FNo\nsingleSelect -> Choice\nmultipleSelects -> Choice with multiple selections\nmultipleRecordLinks, single preferred -> Lookup column\nmultipleRecordLinks, many-to-many -> multi-lookup, junction list, or text fallback after review\nmultipleAttachments -> list attachments or document library strategy\nemail -> Single line of text or Person column candidate\ncollaborator\u002Fperson-like field -> Person\u002FGroup column when resolvable, text fallback otherwise\naiText or (AI) -> Multiple lines of text, AI-derived with regeneration gap\nformula\u002Fcount\u002Frollup -> stored value or calculated column if simple\n```\n\nRelationship rules:\n\n- Use SharePoint lookup columns for simple one-to-many lookups.\n- Do not create both sides of a reverse relationship unless explicitly needed.\n- For many-to-many relationships, ask whether to:\n  - create a junction list,\n  - use a multi-lookup column,\n  - store source linked record names\u002FIDs as text,\n  - or recommend Dataverse instead.\n- If SharePoint lookup limits or delegation concerns are likely, flag them in the plan.\n\nSharePoint user\u002Fpeople picker handling:\n\n- Use SharePoint Person\u002FGroup columns for person-like fields when users can be resolved.\n- Preserve source person data in text columns such as `Source Name`, `Source Email`, and `Airtable Record ID`.\n- Resolve users in this priority:\n  1. Entra\u002FAAD object ID, if available.\n  2. UPN\u002Femail.\n  3. SharePoint site user lookup.\n  4. Display name only as manual review, never automatic.\n- Classify each source person:\n  - `active_match`\n  - `external_or_guest`\n  - `multiple_match`\n  - `no_match`\n  - `missing_identifier`\n  - `manual_review`\n- If a user cannot be resolved, leave the Person\u002FGroup field blank, keep the text\u002Femail fields, and report the gap.\n\nSharePoint suitability warnings:\n\n- SharePoint Lists are not a full Dataverse replacement for complex relational apps.\n- If the Airtable app has many linked tables, row-level security needs, complex business rules, or high-scale app requirements, recommend Dataverse.\n\n## Phase 8: SharePoint auth preflight\n\nRun this if the user selected SharePoint Lists or Both.\n\nBefore auth, ask which execution path to use if it was not already captured:\n\n```text\n1. SharePoint\u002FGraph MCP\n2. PnP PowerShell interactive\n3. Plan only\n```\n\nUse SharePoint\u002FGraph MCP when the agent environment has it configured. Use PnP PowerShell interactive when MCP setup is not available or the user prefers local\u002Fcustomer-run scripting.\n\n### SharePoint\u002FGraph MCP path\n\nSteps:\n\n1. Detect SharePoint\u002FGraph MCP availability.\n2. If unavailable, offer PnP PowerShell interactive as fallback.\n3. Trigger or guide Microsoft Graph\u002FSharePoint interactive sign-in.\n4. Instruct the user to sign in to the target tenant account.\n5. Use the SharePoint site URL collected in Target details intake; if missing, ask before proceeding.\n6. Run read-only validation:\n   - current user\n   - target site exists\n   - list read permission\n   - list creation permission if creating new lists\n   - user resolution capability for Person\u002FGroup fields\n7. Display:\n   - signed-in user\n   - site URL\n   - site title\u002Fid when available\n   - permission summary\n\nDo not create lists during preflight.\n\n### PnP PowerShell interactive path\n\nUse this when SharePoint\u002FGraph MCP is unavailable or the user selects PnP PowerShell.\n\nPreflight behavior:\n\n1. Check whether `PnP.PowerShell` is installed.\n2. If missing, ask for approval to install it for the current user:\n\n```powershell\nInstall-Module PnP.PowerShell -Scope CurrentUser\n```\n\n3. Connect interactively:\n\n```powershell\nConnect-PnPOnline -Url \"\u003CsiteUrl>\" -Interactive\n```\n\n4. Validate the connection with read-only calls:\n\n```powershell\nGet-PnPWeb\nGet-PnPList\n```\n\n5. Validate list creation permission with a non-destructive permission check where possible. Do not create test lists unless the user approves.\n6. Validate user resolution capability for Person\u002FGroup fields with:\n\n```powershell\nEnsure-PnPUser -LoginName \"\u003CuserPrincipalNameOrEmail>\"\n```\n\nUse this only for sample\u002Fapproved users during preflight.\n\nDo not create lists during preflight.\n\n## Phase 9: SharePoint list creation and validation\n\nRun only after explicit user approval.\n\nUse the selected SharePoint execution path:\n\n- SharePoint\u002FGraph MCP, if selected and available.\n- PnP PowerShell, if selected.\n\nCreation order:\n\n1. Create\u002Freuse SharePoint lists for independent tables.\n2. Create\u002Freuse text, number, date, choice, multi-choice, multiline text, and source ID columns.\n3. Create lookup columns after target lists exist.\n4. Create Person\u002FGroup columns where approved.\n5. Validate list schemas.\n\nCreation must be idempotent:\n\n- If list\u002Fcolumn exists and matches, reuse it.\n- If list\u002Fcolumn exists and conflicts, stop and report schema drift.\n- Do not silently overwrite incompatible list schema.\n\nPnP PowerShell implementation guidance:\n\n```powershell\nConnect-PnPOnline -Url \"\u003CsiteUrl>\" -Interactive\nNew-PnPList -Title \"\u003CListTitle>\" -Template GenericList\nAdd-PnPField -List \"\u003CListTitle>\" -DisplayName \"\u003CColumnName>\" -InternalName \"\u003CInternalName>\" -Type Text\nAdd-PnPField -List \"\u003CListTitle>\" -DisplayName \"\u003CColumnName>\" -InternalName \"\u003CInternalName>\" -Type Note\nAdd-PnPField -List \"\u003CListTitle>\" -DisplayName \"\u003CColumnName>\" -InternalName \"\u003CInternalName>\" -Type Number\nAdd-PnPField -List \"\u003CListTitle>\" -DisplayName \"\u003CColumnName>\" -InternalName \"\u003CInternalName>\" -Type DateTime\n```\n\nUse field XML for more complex column types when required:\n\n- Choice\n- MultiChoice\n- Lookup\n- LookupMulti\n- User\n- UserMulti\n\nFor Person\u002FGroup fields, use SharePoint user fields and resolve people with `Ensure-PnPUser`.\n\nFor lookup fields, create target lists first, then create lookup columns after the lookup target exists.\n\nWrite:\n\n```text\nanalysis\u002Fsharepoint-list-validation.json\n```\n\n## Phase 10: SharePoint data import\n\nRun only after list schema validation and explicit user approval.\n\nUse the selected SharePoint execution path:\n\n- SharePoint\u002FGraph MCP, if selected and available.\n- PnP PowerShell, if selected.\n\nImport rules:\n\n- Import lists in dependency order.\n- Store Airtable record ID on every item.\n- Build Airtable record ID to SharePoint item ID maps.\n- Resolve lookup columns from those maps.\n- Resolve Person\u002FGroup fields only when approved and resolvable.\n- Leave unresolved Person\u002FGroup fields blank and preserve source text\u002Femail.\n- Migrate AI fields as multiline text.\n- Do not enable flows or automations during data import.\n\nPnP PowerShell implementation guidance:\n\n```powershell\nAdd-PnPListItem -List \"\u003CListTitle>\" -Values @{\n  \"Title\" = \"\u003Cvalue>\"\n  \"AirtableRecordId\" = \"\u003Crec...>\"\n}\n```\n\nFor lookup fields:\n\n- Import target lists first.\n- Query created items and build Airtable record ID to SharePoint item ID maps.\n- Write lookup columns with SharePoint item IDs.\n\nFor Person\u002FGroup fields:\n\n- Resolve each approved user with `Ensure-PnPUser`.\n- Write the Person\u002FGroup field using the resolved SharePoint user identity\u002Fid format supported by the installed PnP version.\n- If resolution fails, leave Person\u002FGroup blank and preserve source name\u002Femail text fields.\n\nFor large imports:\n\n- Batch logically by list.\n- Add retry\u002Fbackoff for throttling.\n- Write progress logs under `logs\u002F`.\n- Do not ask for approval per item; ask once per import phase unless the runtime forces per-write prompts.\n\nWrite:\n\n```text\nanalysis\u002Fsharepoint-data-import-report.json\n```\n\nValidate:\n\n- source vs SharePoint item counts\n- lookup resolution counts\n- Person\u002FGroup resolution counts\n- skipped\u002Funresolved users\n- choice value mapping\n- AI value preservation\n\n## Phase 11: Review Dataverse plan with user\n\nRun this if the user selected Dataverse or Both.\n\nBefore Dataverse MCP sign-in, show the plan:\n\n- target solution display name, if known\n- tables to create\n- choices to create\n- relationships to create\n- AI fields and migration gaps\n- identity mapping approach\n- Owner handling\n- import load order\n- known gaps\n\nAsk for approval to proceed to Dataverse MCP auth preflight.\n\n## Phase 12: Dataverse MCP auth preflight\n\nRun this if the user selected Dataverse or Both.\n\nThe skill must handle Dataverse MCP connection before creation.\n\nSteps:\n\n1. Detect Dataverse MCP availability.\n2. If unavailable, stop and tell the user Dataverse MCP must be configured in this agent environment.\n3. Trigger Dataverse MCP interactive sign-in.\n4. Instruct user to sign in to the target tenant account.\n5. Use the Dataverse environment URL collected in Target details intake; if missing, ask before proceeding.\n6. Run read-only validation:\n   - WhoAmI\u002Fcurrent user\n   - org\u002Fenvironment URL\n   - metadata read check\n   - solutions query\n7. Display:\n   - signed-in user\n   - org URL\n   - tenant\u002Fenvironment context if available\n8. Use the solution name collected in Target details intake; if missing, ask before proceeding.\n\nDo not create anything during preflight.\n\n## Phase 13: Solution resolution and prefix derivation\n\nRun this if the user selected Dataverse or Both.\n\nAll Dataverse objects must be created inside a solution.\n\nGiven a solution name from the user:\n\n1. Query solutions by unique name and display\u002Ffriendly name.\n2. If exactly one solution matches:\n   - use it\n   - expand publisher\n   - read `publisherid.customizationprefix`\n   - update schema plan with resolved unique name and prefix\n3. If multiple solutions match:\n   - ask the user to choose one\n4. If no solution matches:\n   - ask whether to create a new solution\n   - ask\u002Fselect publisher\n   - derive prefix from publisher, not solution name\n\nFor Web API metadata creation, include:\n\n```text\nMSCRM.SolutionUniqueName: \u003Csolution unique name>\n```\n\nRead-only lookup shape:\n\n```http\nGET \u002Fapi\u002Fdata\u002Fv9.2\u002Fsolutions?$select=uniquename,friendlyname,version&$expand=publisherid($select=customizationprefix,friendlyname)\n```\n\nFilter locally or use supported OData filters for exact unique\u002Fdisplay name matching.\n\n## Phase 14: Final approval before Dataverse creation\n\nRun this if the user selected Dataverse or Both.\n\nShow:\n\n- environment URL\n- signed-in user\n- solution unique name and display name\n- publisher and prefix\n- tables\u002Fcolumns\u002Fchoices\u002Frelationships to create\n- whether existing objects will be reused\n- schema drift warnings\n- data import will not run yet\n\nAsk:\n\n> Approve Dataverse schema creation in this environment and solution?\n\nProceed only on explicit approval.\n\n## Phase 15: Create Dataverse schema\n\nRun this if the user selected Dataverse or Both.\n\nCreation order:\n\n1. Create or reuse solution, if approved.\n2. Create\u002Freuse global choices.\n3. Create\u002Freuse tables.\n4. Create\u002Freuse columns.\n5. Create\u002Freuse relationships.\n6. Create\u002Freuse alternate keys on Airtable Record ID.\n7. Publish customizations.\n8. Read back metadata and verify.\n\nDefault table pattern:\n\n```text\nTicket Category\nTeam Member\nSupport Ticket\n```\n\nDefault choice pattern:\n\n```text\nStatus -> Choice\nPriority -> Choice\nSubcategory -> Choice\nRole -> Choice\nDepartment -> Choice\nSkills -> Multi-select Choice\n```\n\nDefault AI field pattern:\n\n```text\n\u003CAI field> -> Multiline Text, aiDerived metadata in plan\u002Freport\n```\n\nDefault identity pattern:\n\n```text\nTeam Member.Email -> email column\nTeam Member.Mapped Dataverse User -> optional systemuser lookup\nSupport Ticket.Assigned Team Member -> Team Member lookup\nSupport Ticket.Assigned System User -> optional systemuser lookup\nOwner -> unchanged\n```\n\nCreation must be idempotent:\n\n- If an object exists and matches, reuse it.\n- If it exists and conflicts, stop and report schema drift.\n- Do not silently overwrite incompatible metadata.\n\n## Phase 16: Validate Dataverse schema\n\nRun this if the user selected Dataverse or Both.\n\nAfter creation, verify:\n\n- solution exists\n- publisher prefix matches plan\n- all choices exist with expected values\n- all tables exist\n- all columns exist\n- all relationships exist\n- Airtable Record ID columns exist\n- alternate keys exist or are queued\u002Fcreated\n- AI fields are multiline text\n- Skills is multi-select choice\n- Owner was not changed\n- optional `systemuser` lookups exist but are empty\n\nWrite:\n\n```text\nanalysis\u002Fdataverse-schema-validation.json\n```\n\n## Phase 17: Approval before Dataverse import\n\nRun this if the user selected Dataverse or Both.\n\nShow schema validation summary.\n\nAsk:\n\n> Approve data import from Airtable export into Dataverse?\n\nProceed only on explicit approval.\n\n## Phase 18: Import Dataverse data\n\nRun this if the user selected Dataverse or Both.\n\nLoad order:\n\n1. Ticket Category\n2. Team Member\n3. Support Ticket\n\nRules:\n\n- Store Airtable record ID on every row.\n- Build Airtable record ID to Dataverse GUID maps after each table load.\n- Resolve linked-record fields using those maps.\n- Migrate AI values from:\n  - raw text value, when present\n  - `value` property, when Airtable returns `{ state, value, isStale }`\n- Null\u002Fstale AI values do not block import.\n- Keep Owner unchanged.\n- Leave optional `systemuser` lookups empty unless identity mapping is approved.\n\nWrite:\n\n```text\nanalysis\u002Fdataverse-data-import-report.json\n```\n\nValidate:\n\n- record counts\n- lookup resolution\n- skipped\u002Fnull fields\n- AI value preservation\n- choice value mapping\n- Owner unchanged\n\n## Phase 19: Post-migration app target and automation branches\n\nAfter the selected data target schema\u002Flist creation and data import validation, ask:\n\n> What app experience do you want to generate from the migrated Dataverse model?\n\nOffer choices:\n\n1. Plan only.\n2. Generate Code App.\n3. Generate Canvas App.\n4. Generate both Code App and Canvas App.\n\nThen ask separately:\n\n> Do you want to migrate Airtable automations into draft Power Automate flows?\n\nDo not start app or automation generation automatically. App generation and automation migration are optional, approval-gated phases.\n\n## Phase 20: App modernization planning branch\n\nRun this for Code App, Canvas App, both, or plan-only. This is shared UX\u002Fapp planning before target-specific generation.\n\n### UX evidence intake\n\nAsk the user for:\n\n- screenshots of each Airtable Interface page\n- optional screen recording or walkthrough\n- page names and navigation order\n- user roles\u002Fpersonas\n- important forms, grids, dashboards, filters, tabs, and buttons\n- expected behavior for each important button\u002Faction\n- role-specific visibility or permissions, if any\n\nOptional evidence:\n\n- Airtable page source HTML\n- authenticated `readForPages` response JSON, if the user can capture it safely\n- automation screenshots that explain button\u002Faction behavior\n\nNever treat page source alone as a complete UI export. Page source can provide app\u002Fpage\u002Ftable IDs and clues, but it is not enough for full UX reconstruction.\n\n### UX planning\n\nGenerate:\n\n```text\nanalysis\u002Fapp-modernization-plan.json\nanalysis\u002Fcode-app-plan.json\nanalysis\u002Fcanvas-app-plan.json\nanalysis\u002Finterface-reconstruction-plan.json\nreports\u002FUX-Reconstruction-Plan.docx, if DOCX tooling is available\n```\n\nIf no Airtable Interface screenshots are available, generate schema-derived app plans:\n\n- Dashboard\n- Ticket list\n- Ticket detail\u002Fedit\n- Team Members\n- Categories\n- AI insight panels\n\nIf screenshots or workflow notes exist, reconstruct UX from them.\n\nMap Airtable UX patterns as:\n\n```text\nGrid view -> table\u002Flist page\nForm view -> create\u002Fedit form\nGallery -> card gallery\nKanban -> board\nCalendar -> calendar component\nDashboard\u002Finterface summary -> KPI cards and charts\nFiltered view -> saved filter\u002Ftab\nButton -> command\u002Faction placeholder until behavior is confirmed\n```\n\n### App target selection rules\n\nUse the selected Microsoft data platform foundation for all app targets. Dataverse is preferred for richer app generation; SharePoint Lists are supported for list-centric Canvas Apps and lightweight app experiences.\n\nRecommend **Code App** when:\n\n- the customer needs custom React\u002FTypeScript UX\n- advanced components are needed\n- complex layouts or custom interactions are expected\n- developer-owned source code is preferred\n- the app should feel like a bespoke web app\n\nRecommend **Canvas App** when:\n\n- the customer wants low-code maker ownership\n- standard forms\u002Fgalleries\u002Fscreens are sufficient\n- fast iteration inside Power Platform is preferred\n- Dataverse-native forms and Power Fx are a good fit\n- business users will maintain the app\n\nRecommend **Both** when:\n\n- Code App is useful for advanced\u002Fend-user UX\n- Canvas App is useful for admin\u002Fback-office\u002Foperations\n- the customer wants both pro-code and low-code entry points over the same Dataverse model\n\nRecommend **Plan only** when:\n\n- app tooling is unavailable\n- the user wants to review UX first\n- screenshots\u002Fworkflows are insufficient for generation\n\n## Phase 21: Code App generation branch\n\nRun this only if the user selected Code App or Both.\n\nIf Code App generation tools are available in the current agent environment:\n\n1. Reuse the selected target context established during migration.\n2. Add the migrated Dataverse tables or SharePoint Lists as data sources, depending on the selected target.\n3. Generate first-pass React\u002FTypeScript Code App structure from `analysis\u002Fcode-app-plan.json`.\n4. Wire list\u002Fdetail\u002Fcreate\u002Fedit screens to the selected data target.\n5. Add dashboard\u002FKPI components where clear from schema or screenshots.\n6. Add AI-derived fields as read-only\u002Fdisplay panels unless the user asks for regeneration actions.\n7. Leave button\u002Faction behavior as TODOs unless explicitly described by automation evidence or workflow notes.\n\nIf Code App tooling is unavailable, produce a complete app generation plan and stop.\n\nGenerate or update:\n\n```text\nanalysis\u002Fcode-app-plan.json\nreports\u002FCode-App-Plan.docx, if DOCX tooling is available\napps\u002Fcode-app\u002F, if Code App generation tooling is available\n```\n\n## Phase 22: Canvas App generation branch\n\nRun this only if the user selected Canvas App or Both.\n\nIf Canvas App\u002FPower Apps generation tooling is available in the current agent environment:\n\n1. Reuse the selected target context established during migration.\n2. Add the migrated Dataverse tables or SharePoint Lists as data sources.\n3. Generate a first-pass Canvas App plan from `analysis\u002Fcanvas-app-plan.json`.\n4. Create screens for list\u002Fdetail\u002Fcreate\u002Fedit flows.\n5. Use galleries, forms, cards, filters, and command buttons where appropriate.\n6. Generate Power Fx formulas for navigation, filtering, submit, patch\u002Fupdate, and validation where behavior is known.\n7. Add dashboard\u002FKPI screens where clear from schema or screenshots.\n8. Add AI-derived fields as read-only\u002Fdisplay controls unless the user asks for regeneration actions.\n9. Leave unknown button\u002Faction behavior as TODOs unless explicitly described by automation evidence or workflow notes.\n\nIf Canvas App tooling is unavailable, produce a complete Canvas App generation plan and stop.\n\nGenerate or update:\n\n```text\nanalysis\u002Fcanvas-app-plan.json\nreports\u002FCanvas-App-Plan.docx, if DOCX tooling is available\napps\u002Fcanvas-app\u002F, if Canvas App generation tooling is available\n```\n\nCanvas App plan should include:\n\n- app name\n- Dataverse data sources\n- screen list\n- controls per screen\n- galleries\u002Fforms\u002Fcards\n- navigation formulas\n- filter\u002Fsearch formulas\n- submit\u002Fupdate formulas\n- Power Automate integration hooks\n- known behavior gaps\n- maker follow-up checklist\n\n## Phase 23: UX caveat to show the user\n\nAlways state:\n\n> The generated app is a first-pass scaffold based on Dataverse schema and provided screenshots. End-to-end screen behavior, role-specific behavior, button logic, validations, conditional visibility, and automation-driven behavior require additional workflow prompts and validation.\n\n## Phase 24: Automation draft migration branch\n\nRun this only if the user asks to migrate Airtable automations.\n\n### Automation evidence intake\n\nAsk for:\n\n- screenshots of each Airtable automation\n- trigger type\n- target table\u002Fview\n- trigger conditions\n- action list and order\n- email\u002FTeams\u002Fmessage templates\n- update-record field mappings\n- scripts used in custom script actions\n- webhook URLs or integration names, without secrets\n- whether each automation should be enabled immediately or left disabled for review\n\nPreferred evidence:\n\n```text\nautomations\u002F\n  screenshots\u002F\n  automation-notes.md\n  scripts\u002F\n```\n\n### Automation analysis\n\nGenerate:\n\n```text\nanalysis\u002Fautomation-conversion-plan.json\nflows\u002F\u003Cflow-name>.draft.json\nreports\u002FAutomation-Migration-Plan.docx, if DOCX tooling is available\n```\n\nClassify each automation:\n\n```text\nhigh_confidence\nneeds_user_confirmation\nrequires_manual_rebuild\nblocked_missing_details\n```\n\nMap Airtable automation patterns as:\n\n```text\nRecord created trigger -> Power Automate Dataverse row added trigger\nRecord updated trigger -> Power Automate Dataverse row modified trigger\nRecord matches conditions -> Dataverse trigger plus condition block\nScheduled trigger -> recurrence trigger\nSend email -> Outlook connector or Dataverse\u002Femail pattern, depending customer preference\nSend Teams message -> Teams connector\nUpdate record -> Dataverse update row\nCreate record -> Dataverse add row\nFind records -> Dataverse list rows with filter\nCustom script -> Power Automate expression, Azure Function, plugin\u002Faction, or manual rebuild\nWebhook\u002Fintegration -> HTTP action\u002Fcustom connector, with secrets supplied outside chat\n```\n\n### Flow MCP \u002F Power Automate creation\n\nIf Flow MCP or Power Automate MCP is available:\n\n1. Reuse the selected target context established during migration.\n2. Validate Flow MCP sign-in and target environment.\n3. Create flows as draft\u002Fdisabled when possible.\n4. Use the migrated Dataverse tables or SharePoint Lists and resolved schema\u002Flist names.\n5. Do not enable flows until the user reviews connections, triggers, conditions, and actions.\n6. Do not store secrets in generated files.\n\nIf Flow MCP is unavailable:\n\n1. Generate `analysis\u002Fautomation-conversion-plan.json`.\n2. Generate draft flow definitions or implementation instructions.\n3. Stop and tell the user Flow MCP\u002FPower Automate tooling is needed for actual flow creation.\n\n### Automation caveat to show the user\n\nAlways state:\n\n> Automation drafts are generated from screenshots\u002Fnotes and available metadata. Screenshots may omit hidden conditions, dynamic expressions, connection references, retries, permissions, and secrets. Flows must be reviewed before enabling.\n\n## Phase 25: DOCX reporting branch\n\nRun this after each major planning phase if DOCX generation tooling is available. If no DOCX tooling is available, keep JSON\u002FMarkdown outputs and state that DOCX generation was skipped.\n\nCreate a `reports\u002F` folder and generate readable Word documents for business and technical review:\n\n```text\nreports\u002F\n  Data-Migration-Plan.docx\n  SharePoint-Migration-Plan.docx\n  UX-Reconstruction-Plan.docx\n  App-Modernization-Plan.docx\n  Code-App-Plan.docx\n  Canvas-App-Plan.docx\n  Automation-Migration-Plan.docx\n  End-to-End-Migration-Summary.docx\n```\n\n### Data-Migration-Plan.docx\n\nInclude:\n\n- executive summary\n- source Airtable inventory\n- target platform selection: Dataverse, SharePoint Lists, Both, or Plan only\n- collected target details and validation status\n- target Dataverse solution\u002Fenvironment, if Dataverse is selected\n- target SharePoint site\u002Flists, if SharePoint is selected\n- table mapping\n- column mapping\n- choice mapping\n- relationship mapping\n- Airtable AI field handling\n- identity strategy: Dataverse `systemuser` and\u002For SharePoint Person\u002FGroup fields\n- Owner handling for Dataverse and permission\u002Flist ownership handling for SharePoint\n- migration load order\n- validation plan\n- approval gates\n- risks and open questions\n\n### SharePoint-Migration-Plan.docx\n\nInclude when SharePoint Lists are selected:\n\n- target SharePoint site\n- list mapping\n- column mapping\n- choice\u002Fmulti-choice mapping\n- lookup column strategy\n- many-to-many handling recommendation\n- Person\u002FGroup field mapping\n- source person text\u002Femail preservation\n- unresolved user handling\n- attachment strategy\n- import load order\n- validation plan\n- SharePoint limitations and suitability warnings\n\n### UX-Reconstruction-Plan.docx\n\nInclude:\n\n- UX evidence received\n- screenshots inventory\n- inferred page\u002Fnavigation model\n- Code App pages\u002Froutes\n- data sources\n- component plan\n- dashboard\u002FKPI plan\n- buttons\u002Factions inventory\n- known behavior gaps\n- assumptions\n- user validation checklist\n\nState clearly:\n\n> This is a first-pass UX scaffold plan. End-to-end behavior, conditional visibility, validation logic, role-specific flows, and button behavior require further prompting and user validation.\n\n### App-Modernization-Plan.docx\n\nInclude:\n\n- target app options: Code App, Canvas App, Both, Plan only\n- recommendation matrix\n- selected target\n- shared Dataverse foundation\n- UX evidence received\n- target-specific plan summaries\n- tooling prerequisites\n- implementation sequence\n- approval gates\n- behavior gaps\n\n### Code-App-Plan.docx\n\nInclude when Code App is selected:\n\n- React\u002FTypeScript app structure\n- routes\u002Fpages\n- Dataverse data sources\u002Fclient layer\n- components\n- forms\u002Flist\u002Fdetail screens\n- dashboard\u002FKPI components\n- AI insight display panels\n- command\u002Faction TODOs\n- deployment assumptions\n\n### Canvas-App-Plan.docx\n\nInclude when Canvas App is selected:\n\n- Canvas App screens\n- Dataverse data sources\n- galleries\u002Fforms\u002Fcards\n- Power Fx formulas\n- navigation model\n- filter\u002Fsearch behavior\n- submit\u002Fupdate behavior\n- Power Automate hooks\n- maker follow-up checklist\n\n### Automation-Migration-Plan.docx\n\nInclude:\n\n- automation evidence received\n- automation inventory\n- trigger\u002Faction mapping\n- target Power Automate\u002FFlow design\n- Dataverse tables referenced\n- connector requirements\n- draft flow status\n- secrets\u002Fconnection references that must be supplied by the user\n- confidence classification\n- enablement\u002Freview checklist\n\nState clearly:\n\n> Automation drafts are not production-ready until triggers, connections, dynamic expressions, permissions, retries, and error handling are reviewed.\n\n### End-to-End-Migration-Summary.docx\n\nGenerate at the end of the run. Include:\n\n- what was exported\n- target platform selected\n- what was created\u002Freused in Dataverse, if selected\n- what was created\u002Freused in SharePoint, if selected\n- what data was imported\n- validation results\n- UX scaffold status\n- selected app target\n- Code App status, if requested\n- Canvas App status, if requested\n- automation draft status\n- unresolved gaps\n- recommended next steps\n\nThe DOCX files are reader-friendly companions to the JSON artifacts. JSON remains the authoritative machine-readable input for subsequent phases.\n\n## Completion\n\nAt completion, report:\n\n- export folder\n- assessment files\n- report files\n- Dataverse environment\n- SharePoint site, if selected\n- solution\n- prefix\n- Dataverse tables created\u002Freused, if selected\n- SharePoint lists created\u002Freused, if selected\n- data imported\u002Fskipped\n- identity mapping status\n- AI fields migrated with regeneration gap\n- UX scaffold status, if requested\n- app target selected\n- Code App generated\u002Fplanned, if requested\n- Canvas App generated\u002Fplanned, if requested\n- automation draft\u002Fflow status, if requested\n- remaining behavior gaps and required user validation\n",{},"main","30bfe45d279a77276e71a3ac58c35119fc194365","Power Platform Migration Factory\u002FAirtable to Power Platform Migration",20,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills","https:\u002F\u002Fgithub.com\u002Fmicrosoft","https:\u002F\u002Fopensource.microsoft.com","Open source projects and samples from Microsoft","2026-11-14 00:21:20",{"source":7,"skillName":5,"commands":42,"prompt":52,"zipAvailable":53},[43,46,49],{"tool":44,"command":45},"npx","npx skills add microsoft\u002Fpower-cat-skills --skill \"Airtable to Power Platform Migration\"",{"tool":47,"command":48},"bunx","bunx skills add microsoft\u002Fpower-cat-skills --skill \"Airtable to Power Platform Migration\"",{"tool":50,"command":51},"pnpm","pnpm dlx skills add microsoft\u002Fpower-cat-skills --skill \"Airtable to Power Platform Migration\"","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002FSKILL.md",true,[55,61,65,71],{"path":56,"resourceType":57,"resourceTypeDesc":58,"sizeBytes":59,"sourceHtmlUrl":60},"HOW-TO-USE.md","REFERENCE","参考文档",23183,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002FHOW-TO-USE.md",{"path":62,"resourceType":57,"resourceTypeDesc":58,"sizeBytes":63,"sourceHtmlUrl":64},"README.md",2055,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002FREADME.md",{"path":66,"resourceType":67,"resourceTypeDesc":68,"sizeBytes":69,"sourceHtmlUrl":70},"run.py","SCRIPT","脚本",703,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002Frun.py",{"path":72,"resourceType":57,"resourceTypeDesc":58,"sizeBytes":73,"sourceHtmlUrl":74},"skill.yaml",818,"https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002FPower Platform Migration Factory\u002FAirtable to Power Platform Migration\u002Fskill.yaml",[76,102,140,165,188,207],{"skillNo":77,"name":78,"nameZh":6,"description":79,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":80,"categories":81,"keywords":83,"publishedAt":28},"01M711KHT2PNDCPT1AJ06PRTAD","powercat-skills-router","Route Microsoft Power Platform requests to the best-fit specialist skill across microsoft\u002Fpower-cat-skills and microsoft\u002Fpower-platform-skills. Use when a user asks which skill can help, wants to find or use a Power Platform skill, or requests work involving Power Apps, Power Automate, Power Pages, Dataverse, Copilot Studio, or Power Platform administration. Discover candidates, reconcile installation and updates, obtain approval for changes, load the selected skill, and continue the original task.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-skills-router\u002Fskills\u002Fpowercat-skills-router\u002FSKILL.md",[82],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[84,85,86,87,24,88,89,90,91,92,93,94,95,96,97,98,99,27,100,101],"router","powercat skills router","which","discover","copilot","apps","when","updates","copilot studio","dataverse","studio","across","route","work","reconcile","automate","for","fit",{"skillNo":103,"name":104,"nameZh":6,"description":105,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":122,"publishedAt":28},"01M711KBER1KD9NQQ1NSDMF8F1","eval-generator-gen-pages","Generate a three-layer eval suite (presence checks + unit tests + security analysis) for Power Apps Generative Pages in Model-Driven Apps. Generative pages are single-file React\u002FTypeScript components using Fluent UI V9 and the dataApi prop for Dataverse operations — NOT Code Apps, NOT PCF components. Code may be generated by the App Agent in make.powerapps.com or by AI code generation tools (Claude Code, GitHub Copilot CLI) using the \u002Fgenpage skill. Always produces: evals\u002Fmanifest.json, evals\u002Fpresence\u002F\u003Cid>.check.ts, evals\u002Funit\u002F\u003Cfeature>.test.tsx, evals\u002Frunner\u002Frun-evals.ts, evals\u002Frunner\u002Fpresence-runner.ts, evals\u002Frunner\u002Fsecurity-runner.ts, and evals\u002Fdashboard\u002Findex.html. Triggers: 'eval my generative page', 'generate evals for gen page', 'review my genpage code', 'test my generative page', 'check my model driven app page', 'eval generator gen pages'.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-procode-eval\u002Fskills\u002Feval-generator-gen-pages\u002FSKILL.md",[108,111,114,117],{"categoryNo":109,"categoryName":110,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000008","测试与质量",{"categoryNo":112,"categoryName":113,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":115,"categoryName":116,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":118,"categoryName":119,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",[123,124,125,126,127,128,129,130,24,131,89,132,93,133,134,135,136,137,138,139],"eval","generator","eval generator","eval generator gen pages","pages","unit","app","tsx","generative","URL","components","fluent","react","github copilot cli","generate","eval suite","run",{"skillNo":141,"name":142,"nameZh":6,"description":143,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":144,"categories":145,"keywords":155,"publishedAt":28},"01M711K4VSKBM85NYF3C5QQZQF","eval-generator-code-app","Generate a two-layer eval suite (presence checks + static security analysis) for a Power Apps Code App. Code Apps use @microsoft\u002Fpower-apps SDK with generated service classes in src\u002Fgenerated\u002Fservices\u002F — NOT @microsoft\u002Fpowerapps-component-framework or context.webAPI.*. BRD is optional — if absent, features are derived from a code review of the project. Always produces: evals\u002Fmanifest.json, evals\u002Fpresence\u002F\u003Cid>.check.ts files, evals\u002Frunner\u002Frun-evals.ts, evals\u002Frunner\u002Fpresence-runner.ts, evals\u002Frunner\u002Fsecurity-runner.ts, and evals\u002Fdashboard\u002Findex.html. Triggers: 'generate code app evals', 'eval my code app', 'generate tests for code app', 'code app eval generator', 'check feature completeness code app'.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-procode-eval\u002Fskills\u002Feval-generator-code-app\u002FSKILL.md",[146,149,150,151,154],{"categoryNo":147,"categoryName":148,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":112,"categoryName":113,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":115,"categoryName":116,"taxonomyType":20,"taxonomyTypeDesc":21},{"categoryNo":152,"categoryName":153,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000030","开发工程师",{"categoryNo":118,"categoryName":119,"taxonomyType":120,"taxonomyTypeDesc":121},[129,123,124,125,156,157,24,158,159,160,161,89,132,162,137,138,139,163,164,100],"code","eval generator code app","project","static","code review","files","component","security","context",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":171,"publishedAt":28},"01M711JZEWX0N2D7EA74YBCJ9G","powercat-overpage","Reviews the Power Pages site(s) inside a Power Platform solution .zip against best practices across Security, Performance, Accessibility, Maintainability, Architecture and Reliability — by reading the pages, web templates, custom JS\u002FCSS, settings and table permissions and reasoning about them. Optionally also ingests a browser HAR capture (recommended) to investigate real performance bottlenecks and map them to code. Produces a [SolutionName].findings.json (validated against findings.schema.json) with solution-level, per-site and per-component findings, each with a description, a suggested fix, and (where relevant) a code or HAR anchor. Then opens the PowerCAT OverPage viewer with the solution, findings and HAR loaded so the user can explore findings overlaid on a live page preview, on the actual code, and on the network waterfall. Triggers: 'powercat overpage', 'overpage my site', 'review my power pages site', 'review this portal solution', 'evaluate this power pages solution', 'audit power pages site', 'overpage', 'power pages solution review', 'analyze power pages performance', 'review power pages with har'.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-overpage\u002Fskills\u002Fpowercat-overpage\u002FSKILL.md",[],[172,173,174,175,176,24,177,178,179,180,181,156,182,183,95,184,185,186,162,187],"powercat overpage","reviews","reliability","relevant","css","performance","explore","fix","map","preview","architecture","review","analyze","browser","permissions","audit",{"skillNo":189,"name":190,"nameZh":6,"description":191,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":192,"categories":193,"keywords":194,"publishedAt":28},"01M711JWDD22RDQ4HG6XD3V96F","powercat-overflow","Reviews every Power Automate cloud flow inside a Power Platform solution (.zip) against Microsoft's coding guidelines and produces a [SolutionName].findings.json next to the uploaded solution, then opens the hosted PowerCAT-Overflow viewer at https:\u002F\u002Fmicrosoft.github.io\u002Fpower-cat-skills\u002FPowerCAT-Overflow.html and uploads both files so the user can explore the results. Triggers: 'powercat overflow', 'overflow my solution', 'review my solution', 'evaluate flows in this solution', 'audit Power Auto","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-overflow\u002Fskills\u002Fpowercat-overflow\u002FSKILL.md",[],[195,173,24,178,196,161,197,183,198,199,187,200,201,202,203,204,99,205,206,27],"powercat overflow","flows","auto","io","next","at","flow","my","coding","html","viewer","zip",{"skillNo":208,"name":209,"nameZh":6,"description":210,"descriptionZh":6,"repositoryFullName":7,"ownerLogin":8,"ownerAvatarUrl":9,"ownerAccountNo":10,"ownerDisplayName":11,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":211,"categories":212,"keywords":217,"publishedAt":28},"01M711JRDNTWN8E2JXEE5GHB9A","dev-environment-deprecation-report","Builds a \"Developer Environments Deprecation Report\" (HTML) for any Power Platform tenant: days left until\nunmanaged developer environments are suspended, which ones are unmanaged, the apps, flows and agents at risk,\nenvironments created on behalf of other makers, and makers over the one-per-maker limit. Uses the Power\nPlatform for Admins connectors and a bundled generator script. Use when the user asks for a \"developer\nenvironment report\", \"unmanaged developer environments\", \"dev environment deprecation\", \"created on behalf\nof developer environments\", \"one PDE per maker\" or \"days left until developer environment suspension\".\nDo NOT use for production, sandbox, default or Teams environment reports, or general\ninventory\u002Fusage questions — use ask-power-platform-advisor instead.","https:\u002F\u002Fgithub.com\u002Fmicrosoft\u002Fpower-cat-skills\u002Fblob\u002Fmain\u002Fplugins\u002Fpowercat-governance\u002Fskills\u002Fdev-environment-deprecation-report\u002FSKILL.md",[213,214],{"categoryNo":152,"categoryName":153,"taxonomyType":120,"taxonomyTypeDesc":121},{"categoryNo":215,"categoryName":216,"taxonomyType":120,"taxonomyTypeDesc":121},"01JBSEEDCAT000000000000034","行政与办公人员",[218,219,220,221,222,223,224,86,24,225,226,196,227,89,90,228,229,230,231,200],"deprecation","dev environment deprecation report","environment","dev","dev environment","report","tenant","maker","inventory","default","ask","analysis","reports","advisor"]