[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-pulumi-pulumi-migrate-from-discovered-stack":3,"mdc-33zbs5-key":33,"related-org-pulumi-pulumi-migrate-from-discovered-stack":3184,"related-repo-pulumi-pulumi-migrate-from-discovered-stack":3343},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":11,"stars":23,"repoUrl":24,"updatedAt":25,"license":26,"forks":27,"topics":28,"repo":29,"sourceUrl":31,"mdContent":32},"pulumi-migrate-from-discovered-stack","migrate CloudFormation or ARM stacks to Pulumi","Migrate a CloudFormation or ARM stack into a Pulumi stack, sourced from a\nstack that Pulumi Cloud's Discovery feature has already found and exposed\nvia the discovered-stacks API. Load this skill when the user has a\ndiscovered stack in Pulumi Cloud and wants to bring its resources under\nPulumi management. Do NOT load for greenfield Pulumi authoring, raw\ntemplate conversion with no discovered-stack counterpart (i.e. no matching\nentry from the discovered-stacks API), or Terraform migration.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},"pulumi","Pulumi","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fpulumi.png",[12,14,17,20],{"name":9,"slug":8,"type":13},"tag",{"name":15,"slug":16,"type":13},"Migration","migration",{"name":18,"slug":19,"type":13},"Cloud","cloud",{"name":21,"slug":22,"type":13},"Infrastructure as Code","infrastructure-as-code",63,"https:\u002F\u002Fgithub.com\u002Fpulumi\u002Fagent-skills","2026-08-06T06:09:23.16972",null,4,[],{"repoUrl":24,"stars":23,"forks":27,"topics":30,"description":26},[],"https:\u002F\u002Fgithub.com\u002Fpulumi\u002Fagent-skills\u002Ftree\u002FHEAD\u002Fmigration\u002Fskills\u002Fpulumi-migrate-from-discovered-stack","---\nname: pulumi-migrate-from-discovered-stack\ndescription: |\n    Migrate a CloudFormation or ARM stack into a Pulumi stack, sourced from a\n    stack that Pulumi Cloud's Discovery feature has already found and exposed\n    via the discovered-stacks API. Load this skill when the user has a\n    discovered stack in Pulumi Cloud and wants to bring its resources under\n    Pulumi management. Do NOT load for greenfield Pulumi authoring, raw\n    template conversion with no discovered-stack counterpart (i.e. no matching\n    entry from the discovered-stacks API), or Terraform migration.\n---\n\n**Scope: this skill only applies to stacks Pulumi Cloud's Discovery feature has already scanned and exposed through the discovered-stacks API** (`GET ...\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fresources`, see below). It is not for migrating an arbitrary CloudFormation\u002FARM template or account that Discovery hasn't scanned yet — if no discovered stack exists for the source, this skill has nothing to read and does not apply.\n\n> **Do not load `cloudformation-to-pulumi` or `pulumi-arm-to-pulumi` alongside this skill.** Those two skills prescribe a template-first workflow (mechanical translation → import) and mandate `aws-native` for AWS. This skill is cloud-state-first (import from discovered state → optional refactor against the template later) and defaults to `aws` classic \u002F `azure-native`. The useful reference material from those two skills has been curated into [`cloudformation.md`](cloudformation.md) and [`arm.md`](arm.md) in this folder.\n\n---\n\n## Plan adjustment\n\nIf you already generated a migration plan before loading this skill, review it against the workflow below and update it — the phases here supersede any earlier plan. Communicate the adjusted plan to the user before proceeding.\n\n## Success criteria\n\nA migration is complete when:\n\n1. **Complete resource coverage** — every discovered resource is imported OR has an annotation explaining why not.\n2. **Zero-diff** — `pulumi preview` shows no changes. This proves the code matches the cloud state exactly.\n3. **Progress tracked via the API** — use `compareTo` and migration annotations so progress is visible in Pulumi Cloud, not just in agent memory.\n4. **PR as the output** — a pull request with the migrated code and a migration report.\n\n## THE DISCOVERED-STACKS API\n\n### Fetching resources\n\n```\nGET \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fresources?compareTo={targetProject}\u002F{targetStack}\n```\n\nAlways include `compareTo` if the target Pulumi stack exists (it may already have state from a previous migration attempt). Returns a list of `DiscoveredResourceInfo` objects. **The JSON paths below are exact — verify before consuming:**\n\n-   `name` — top-level: logical name (CF Logical ID \u002F ARM resource name). **Use this as the Pulumi resource name.**\n-   `originType` — top-level: native cloud type (e.g. `AWS::S3::Bucket`, `Microsoft.Storage\u002FstorageAccounts`)\n-   `providerType` — top-level: mapped Pulumi type token (e.g. `aws:s3\u002Fbucket:Bucket`). `null` if unmapped.\n-   `resource.inputs.providerId` — physical cloud ID for `pulumi import`.\n-   `resource.urn` — the URN to use as `resourceUrn` in annotation requests (copy verbatim).\n-   `migrationStatus` — top-level: one of the statuses below.\n-   `annotation` — top-level: user\u002Fagent annotation if one exists (see Annotations below).\n\nThe `resource.inputs` object also carries raw cloud-provider data:\n\n**For CloudFormation** — `resource.inputs.cloudFormation`:\n\n-   `physicalResourceId` — the original CF physical ID\n-   `resourceType` — the CF type (e.g. `AWS::IAM::Role`)\n-   `resourceStatus` — e.g. `CREATE_COMPLETE`, `DELETE_COMPLETE`\n-   `driftStatus` — `NOT_CHECKED`, `IN_SYNC`, `DRIFTED`\n\nFor CDK-synthesized CF stacks, `inputs.cdkPath` is also present — see [`cloudformation.md §5`](cloudformation.md) for how to use it.\n\n**For ARM** — `resource.inputs.arm`. ARM resources are grouped by resource group, not by\ndeployment, so a resource with no deployment currently backing it (its deployment history\naged out of Azure's retention window, or it was created outside any tracked deployment) is\nstill returned — just as a placeholder, with `resource.inputs.deploymentName` empty and a\ndifferent `arm` shape:\n\n-   **Deployment-backed** (`resource.inputs.deploymentName` non-empty) — `arm` is a\n    deployment-operation object: `properties.targetResource.id` \u002F `.resourceType` \u002F\n    `.resourceName`, `properties.provisioningState` (e.g. `Succeeded`).\n-   **Placeholder** (`resource.inputs.deploymentName` empty) — `arm` is the raw Azure\n    generic-resource object instead: top-level `id`, `name`, `type`, `location`, `tags`.\n    No `properties.targetResource` — don't look for it.\n\nEither way, prefer the top-level `resource.inputs.providerId` for the import ID (see\nabove) rather than reaching into `arm` — it's already normalized across both shapes.\n\n### Migration statuses\n\nStatuses are PascalCase. First match wins:\n\n1. **`Migrated`** — the resource was found in the `compareTo` Pulumi stack. Already under Pulumi management; skip.\n2. **`Ready`** — `providerType` and `providerId` are set and the scanner confirmed the resource exists. Import with `pulumi import \u003CproviderType> \u003Cname> \u003CproviderId> --generate-code --out \u003Cfile>.ts` (NEVER without `--generate-code --out` — see Phase 4).\n3. **`NotFound`** — `providerType` and `providerId` are set, but the scanner could not confirm the resource's current state. May be deleted, mapping may be imperfect, or scanner hit a gap. Verify before importing.\n4. **`NotApplicable`** — container or wrapper types (`AWS::CloudFormation::Stack`, `Microsoft.Resources\u002Fdeployments`, `Microsoft.Resources\u002FresourceGroups`, `pulumi:providers:*`) are not individually migratable. Skip silently.\n5. **`NoMatch`** — `providerType` is `null`. No mapping found. Common examples:\n    - CF Custom Resources (e.g. `Custom::VpcRestrictDefaultSG`) — no direct Pulumi equivalent.\n    - Inline policies — `AWS::IAM::Policy` modeled as an inline property of `aws:iam\u002Frole:Role`. Once the parent Role is migrated, annotate the policy as migrated.\n6. **`PulumiOnly`** — exists in the `compareTo` stack with no discovered counterpart, or those created to migrate NoMatch resources. Surface to user.\n\nResources with `annotation.statusOverride` should be treated as resolved per the override, even if the computed status disagrees.\n\n### Annotations\n\n```\nPUT  \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fmigration\nDELETE \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fmigration?resourceUrn={urn}\n```\n\nPUT body:\n\n```json\n{\n  \"resourceUrn\": \"\u003Ccopy verbatim from resource.urn in the list response>\",\n  \"note\": \"explanation of what happened\",\n  \"statusOverride\": \"Migrated\" | \"\",\n  \"linkedResourceUrn\": \"\u003Coptional: URN of the Pulumi resource paired 1:1 with this origin>\"\n}\n```\n\nUse the Pulumi Cloud API for all annotation requests. At least one of `note` or `statusOverride` must be non-empty. Omit `statusOverride` entirely (do not send `null`) when updating only the note. The DELETE endpoint clears both the note and any `statusOverride`.\n\nUse annotations to:\n\n-   Flag deleted resources as `Migrated` with a note explaining they no longer exist\n-   Flag inline\u002Fchild resources covered by a parent's migration as `Migrated` with a note naming the parent — **do not** use `linkedResourceUrn` here (it's a 1:many relationship and the UI only merges 1:1 pairs)\n-   Bridge a `NotFound` or `NoMatch` origin to its `PulumiOnly` counterpart after a corrected mapping (`statusOverride=Migrated` + `linkedResourceUrn` → the PulumiOnly URN). This is the only valid use of `linkedResourceUrn`.\n-   Leave notes explaining blockers or manual steps taken\n-   Track decisions for resources the automatic classifier can't resolve\n\nThe annotation endpoint is the shared place to track migration progress — always read existing annotations before acting on a resource, and respect overrides left by the user.\n\nThe `note` field is user-authored context. Treat it as a **high-priority instruction** about that specific resource. Common uses: naming preferences, import ID hints, resources to skip, or special handling instructions. Notes reach the agent through two channels:\n\n1. **Starting prompt** — when the user kicks off a migration task, any note on a selected resource is appended to that resource's line:\n   ```\n   - aws:s3\u002Fbucket:Bucket \"my-bucket\" (provider ID: my-bucket-prod) — note: use logical name \"appBucket\" in code\n   ```\n   Read these before calling the API.\n\n2. **API response** — the `annotation.note` field on each `DiscoveredResourceInfo` when you call `GET ...\u002Fresources`. The `annotation` object is omitted entirely when no annotation has been set.\n\n---\n\n## MIGRATION WORKFLOW\n\n### Phase 0 — Preconditions and scoping\n\nBefore any tool call, gather and confirm **all** of the following. If anything is missing, **ask** — don't proceed with a guess.\n\n**Source (the discovered stack):**\n\n-   Org name (e.g. `pulumi_local`)\n-   Discovered project name (e.g. `AcmeCdkExampleStack`)\n-   Discovered stack name (e.g. `dev-sandbox-disc_us-west-2__Dev`) — this is the scanner-generated name, usually encoding account + region + CF\u002FARM stack name.\n-   Region (confirm even if the stack name suggests it).\n\n**Target (where the Pulumi code and state will live):**\n\n-   **Target git repo URL** — ask the user. All work happens inside this repo from the start.\n-   **Subfolder** (optional) — ask if the user has a preference; default to repo root.\n-   **Target project + stack names** — ask the user, don't invent. If the stack already exists, use `compareTo` in Phase 1; if not, create it in Phase 2.\n-   **Target language** — TypeScript default.\n\n**Refactor preferences** (for Phase 7):\n\n-   Does the user have the **original source code** (CDK repo, Bicep project, Terraform modules)? If yes, path or URL. **This is the primary structural reference for Phase 7** — the refactored Pulumi code will draw on its component boundaries, file layout, and naming conventions as a guide, adapted to what the import model actually produced.\n-   Does the user have a **preferred program layout** for the Pulumi output? (e.g. \"one file per service\", \"match my existing repo shape\", \"I don't care\")\n-   Does the user want Phase 7 at all, or stop after zero-diff (Phase 6)?\n\n**Credentials:**\n\n-   ESC environment for cloud credentials (ask if not given; never invent). ESC is preferred — see [`cloudformation.md §1`](cloudformation.md) or [`arm.md §1`](arm.md).\n\n**Don't start Phase 1 until all of the above are confirmed.** Summarize the plan back to the user and wait for approval.\n\n### Phase 1 — Resource fetch and triage\n\nStart here every time, even when resuming an existing migration. The API + any existing annotations are the source of truth for what's been done so far. If the target repo already has Pulumi code, read it — it tells you the conventions, existing resources, and how far a previous attempt got.\n\n1. Fetch discovered resources: `GET ...\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fresources`.\n    - **Target stack exists** (resumed migration): append `?compareTo=\u003CtargetProject>\u002F\u003CtargetStack>`.\n    - **Target stack does not exist** (greenfield): **omit `compareTo`** — the API returns 404 if the target stack isn't found. After Phase 2 creates the stack, subsequent calls can include it.\n2. **Save the response to disk** — `.\u002F.migration\u002Fresources-baseline.json`.\n3. **Run triage**: `python3 \u003Cskill-base-dir>\u002Fscripts\u002Ftriage.py .migration\u002Fresources-baseline.json` — prints status counts (accounting for annotation overrides) and a per-resource table.\n4. Present the plan to the user:\n    > \"Found N resources. A already Migrated, M Ready, K NotFound, J NoMatch, L non-migratable containers. I'll import Ready first, then verify NotFound, then triage NoMatch with you. Sound good?\"\n\nGet confirmation before writing any code.\n\n### Phase 2 — Target repo and Pulumi stack setup\n\n1. **Clone the target git repo** (from Phase 0) and work inside it for all subsequent phases. If the repo already has code, read it to understand existing conventions and resources before adding new ones.\n2. If the target stack already exists (Phase 0 check), select it. Otherwise:\n    - Create the Pulumi project: `pulumi new \u003Clanguage> --name \u003Cproject> --stack \u003Corg>\u002F\u003Cproject>\u002F\u003Cstack> --yes`.\n3. Set provider config: `pulumi config set aws:region \u003Cr>` (or `azure-native:location`).\n4. Link the ESC environment if provided.\n\n**No empty `pulumi up` needed.**\n\n> Concrete commands for project + stack setup, region config, and provider install: [`cloudformation.md §2`](cloudformation.md) or [`arm.md §2`](arm.md).\n\n### Phase 3 — Build the import file\n\nGenerate the import file: `python3 \u003Cskill-base-dir>\u002Fscripts\u002Fbuild_import.py .migration\u002Fresources-baseline.json .migration\u002Fimport.json`. This filters Ready\u002FNotFound resources (excluding already-annotated ones) and maps API fields to the Pulumi import format (`type` ← providerType, `name` ← name, `id` ← resource.inputs.providerId).\n\n### Phase 4 — Import\n\nUsing the `import.json` from Phase 3.\n\n**Always use `--generate-code --out`** — without it, resources land in state with no code, breaking `pulumi preview`.\n\n```\npulumi import --file import.json --generate-code --out batch.\u003Cext>\n# then: append generated code into the main program file and delete the batch file\n```\n\n**Per-batch loop: import → preview → commit → annotate.** Aim for ~20 resources per batch. For CDK stacks, batch by `cdkPath` top-level group; otherwise batch by resource type prefix.\n\n1. **Import** the batch.\n2. **`pulumi preview`** — zero diff required. Fix any diffs before moving on.\n3. **Commit** the program changes to a branch.\n4. **Annotate** each imported resource — `PUT ...\u002Fmigration` with note and **no `statusOverride`**. Annotations survive context resets and are visible in the UI.\n\n`?compareTo` is a **live progress signal** — `pulumi import` writes state immediately, so `migrationStatus` flips to `Migrated` after each import. **Do not run `pulumi up`** (see Phase 6).\n\n**Reserve `statusOverride`** for cases where the computed status will be wrong:\n\n-   `statusOverride=Migrated` (with `linkedResourceUrn`) — resource covered by another (inline IAM policy → parent Role, IGW attachment → IGW, etc.).\n-   `statusOverride=Migrated` (with a note, no `linkedResourceUrn`) — resource is deleted, dangling, or has no Pulumi equivalent. Flag it resolved so it drops out of the outstanding work.\n\n### Phase 5 — NotFound and NoMatch triage\n\n**Default strategy: try first, annotate second.** For both NotFound and corrected-mapping cases, attempting `pulumi import` is the fastest way to learn what's actually wrong. The error messages are precise and actionable.\n\n**NotFound** (`providerType` set, state unconfirmed):\n\nCommon outcomes:\n\n1. **Resource is deleted.** `pulumi import` returns `Preview failed: resource '\u003Cid>' does not exist`. Annotate `statusOverride=Migrated` with the literal error in the note. **Don't retry.** In practice, a substantial share of NotFound resources turn out to be deleted rather than a mapping error.\n\n2. **Wrong `providerType` mapping.** Import fails with a type-validation error or schema mismatch. Several CF types have multiple valid Pulumi mappings (VPC gateway attachment \u002F VPN vs IGW; S3 vs s3control; RDS instance vs cluster instance; SES v2 vs v1; etc.) — our scanner picks a primary that doesn't always match your resource. **Look up the `originType` in [`cloudformation.md §7`](cloudformation.md)**, override `providerType` in the import file, retry. Then handle the fingerprint side-effect (next bullet).\n\n3. **Wrong-mapping side-effect: PulumiOnly appears.** When the agent imports with a corrected `providerType`, fingerprint matching against the discovered resource fails. The discovered resource stays `NotFound` (or `NoMatch`) and a new `PulumiOnly` entry appears. **Annotate the original origin row as `statusOverride=Migrated` with `linkedResourceUrn` pointing to the PulumiOnly URN.** This bridges them in the UI and keeps the bookkeeping clean.\n\n4. **Resource is alive and mapping is correct.** Import succeeds. Status flips to `Migrated` automatically.\n\n**NoMatch** (`providerType` is `null`):\n\nCommon patterns:\n\n1. **Inline IAM policies.** `AWS::IAM::Policy` whose name matches a migrated Role's prefix is an inline policy already captured as `inlinePolicies` on the Role's import. Annotate `statusOverride=Migrated` with note: `\"inline policy of \u003CRoleName>\"`.\n\n2. **AWS::SecretsManager::SecretTargetAttachment** has no direct Pulumi mapping. The link between secret and target (RDS cluster, etc.) is implicit via the cluster's credentials config. Annotate `statusOverride=Migrated` with a note explaining the implicit link.\n\n3. **CDK Custom Resources** (`Custom::*`). Typically a Lambda handler doing the actual work. Check [`cloudformation.md §5`](cloudformation.md) for known handler → Pulumi replacement mappings. **Don't annotate `Migrated` without confirming with the user** — surface what the handler does and let them decide.\n\n4. **Other NoMatch types.** Look up the `originType` in the cloud provider docs (CF resource type reference or ARM resource type reference) to understand what the resource is, then search the Pulumi registry for a matching provider type. If the mapping is ambiguous, surface to the user and ask.\n\n**Pre-existing PulumiOnly entries.** Beyond the corrected-mapping artifacts above, `PulumiOnly` also covers resources already in the target stack that aren't part of this migration. Leave those as-is — no annotation needed.\n\n> For cloud-specific lookup commands (verifying resources exist, finding import IDs, querying the cloud), provider-choice rules (`aws` classic vs `aws-native`, `azure-native` vs `azure`), the Preview Resolution Workflow, and known import quirks, see [`cloudformation.md §3–§6`](cloudformation.md) or [`arm.md §3–§6`](arm.md).\n\n### Phase 6 — Reconciliation & PR\n\n1. Run `pulumi preview` — **confirm there are NO changes**. Any diff means the generated code doesn't match the imported state. Diffs come in three shapes:\n    - **Removed (`-`)** — a field the cloud has but your code doesn't set. **Add it to the code** with the real cloud value. Don't `ignoreChanges`.\n    - **Added (`+`)** — a field your code sets that the provider didn't return. If computed\u002Fread-only → `ignoreChanges`. If a provider default re-statement → remove from code.\n    - **Changed (`~`)** — value mismatch. Query the cloud, determine the correct value, update code. Never silence with `ignoreChanges`.\n\n    Expect 2–5 preview rounds for complex resources. **Never run `pulumi up` to resolve diffs — that modifies the cloud, not the code.** See [`cloudformation.md §6`](cloudformation.md) or [`arm.md §6`](arm.md) for cloud-specific diff patterns.\n2. Do one final `GET resources?compareTo=...` and verify the expected distribution (this reflects the current backend state — `migrationStatus` is already up-to-date since every `pulumi import` writes state):\n    - `Migrated` — all imported resources\n    - `PulumiOnly` — Pulumi-only resources, including any corrected-mapping imports linked via annotation\n    - `NoMatch` remaining — every one should have an annotation\n    - `NotApplicable` (containers) — silently skipped\n3. Proceed to Phase 7 (refactor offer) **before** opening the PR.\n\nThe migration is functionally complete when preview is clean and the API triage shows no unresolved resources. **Do not run `pulumi up`.** The imported state is already synced to Pulumi Cloud via `pulumi import`; there's nothing for `pulumi up` to do that serves the migration.\n\n---\n\n### Phase 7 — Refactor and maintainability review (before the PR)\n\nZero-diff is achieved, but the imported code is \"flat\" — hardcoded values, no cross-resource references, all resources at the top level. **Before opening the PR**, offer the user a readability refactor.\n\n**7a — Offer and orient**\n\nIf Phase 0 didn't capture explicit refactor preferences, or the user hasn't explicitly declined, **ask now**:\n\n> \"Preview is clean and all resources are accounted for. Before I open the PR, I'd like to refactor the code for maintainability — replacing any hardcoding with cross-resource references, extracting config parameters, and grouping related resources. (If you gave me a source repo, I'll use it as the structural blueprint, matching the intended file layout and component names.) Want me to go ahead?\"\n\nIf they decline, skip to Phase 8.\n\n**7b — Implement the refactor**\n\nRead [`refactor.md`](refactor.md) for strategies, invariants, and template-reading references. Key priorities in order:\n\n1. **Take structural cues from the source repo first** — if the user provided a source repo, read it now (clone or use the local path from Phase 0). Use its file layout, component\u002Fmodule boundaries, and naming conventions as a guide. Where a group of resources maps naturally to a class, module, or subdirectory in the source and that grouping still feels natural for the imported Pulumi program, mirror that structure; otherwise avoid forcing artificial groupings just to match the source mechanically.\n2. **Replace literal ARN\u002FID references** with cross-resource output references.\n3. **Extract config parameters** (region, account ID, environment tag).\n4. **Consolidate into `ComponentResource` classes** where the source repo or CDK paths suggest a natural grouping.\n5. **Split into files** only last — and only when a natural isle warrants it.\n\nRun `pulumi preview` after every non-trivial change. Zero-diff must hold throughout. If preview shows a diff, revert that single change before trying anything else — see [`refactor.md` § The invariant](refactor.md) for recovery steps.\n\n**7c — User walkthrough and maintainability sign-off**\n\nAfter the refactor, **present the result to the user before opening the PR**:\n\n1. Show a summary of what changed: files created\u002Frenamed, components introduced, literals replaced, config keys added.\n2. Walk through the top-level `index.ts` (or equivalent) line by line if it's under ~80 lines; otherwise describe the module breakdown.\n3. Highlight any judgment calls (e.g. \"I grouped the IAM resources into `iam.ts` to match the `lib\u002Fiam\u002F` directory in your source repo — let me know if you'd prefer a different name\").\n4. Ask explicitly: **\"Does this structure match how you'd expect to maintain this code?\"** Wait for the user's answer. If they request changes, make them (always preview after) and repeat the walkthrough until they're satisfied.\n\nOnly proceed to Phase 8 once the user confirms the structure is acceptable.\n\n---\n\n### Phase 8 — PR and migration report\n\nProduce the migration report (see below) and open the PR. The PR includes whatever state the code is in — raw imported code (if the user skipped Phase 7) or the refactored version (if they opted in).\n\n---\n\n## MIGRATION REPORT FORMAT\n\nInclude in the PR description:\n\n1. **Overview** — source discovered stack → target Pulumi stack, region, language.\n2. **Triage summary** — counts by status at start and end.\n3. **Resource mapping table** — name, origin type, provider type, status, notes.\n4. **Gaps** — unmapped resources and why, with annotations.\n5. **Progress URL** — link to the discovered-stacks comparison endpoint for ongoing tracking.\n6. **Next steps** — pending user decisions, optional refactoring.\n",{"data":34,"body":35},{"name":4,"description":6},{"type":36,"children":37},"root",[38,61,138,142,149,154,160,165,226,232,239,251,276,410,423,440,526,550,583,714,733,739,744,965,978,984,993,998,1191,1229,1234,1331,1336,1354,1422,1425,1431,1437,1456,1464,1509,1517,1567,1577,1616,1624,1652,1662,1668,1673,1777,1782,1788,1846,1862,1890,1896,1930,1936,1949,1970,1979,1997,2063,2113,2128,2165,2171,2188,2203,2208,2372,2393,2398,2514,2531,2587,2593,2817,2848,2851,2857,2869,2877,2888,2896,2901,2909,2925,2986,3009,3017,3028,3082,3087,3090,3096,3101,3104,3110,3115,3178],{"type":39,"tag":40,"props":41,"children":42},"element","p",{},[43,50,52,59],{"type":39,"tag":44,"props":45,"children":46},"strong",{},[47],{"type":48,"value":49},"text","Scope: this skill only applies to stacks Pulumi Cloud's Discovery feature has already scanned and exposed through the discovered-stacks API",{"type":48,"value":51}," (",{"type":39,"tag":53,"props":54,"children":56},"code",{"className":55},[],[57],{"type":48,"value":58},"GET ...\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fresources",{"type":48,"value":60},", see below). It is not for migrating an arbitrary CloudFormation\u002FARM template or account that Discovery hasn't scanned yet — if no discovered stack exists for the source, this skill has nothing to read and does not apply.",{"type":39,"tag":62,"props":63,"children":64},"blockquote",{},[65],{"type":39,"tag":40,"props":66,"children":67},{},[68,89,91,97,99,105,107,113,115,125,127,136],{"type":39,"tag":44,"props":69,"children":70},{},[71,73,79,81,87],{"type":48,"value":72},"Do not load ",{"type":39,"tag":53,"props":74,"children":76},{"className":75},[],[77],{"type":48,"value":78},"cloudformation-to-pulumi",{"type":48,"value":80}," or ",{"type":39,"tag":53,"props":82,"children":84},{"className":83},[],[85],{"type":48,"value":86},"pulumi-arm-to-pulumi",{"type":48,"value":88}," alongside this skill.",{"type":48,"value":90}," Those two skills prescribe a template-first workflow (mechanical translation → import) and mandate ",{"type":39,"tag":53,"props":92,"children":94},{"className":93},[],[95],{"type":48,"value":96},"aws-native",{"type":48,"value":98}," for AWS. This skill is cloud-state-first (import from discovered state → optional refactor against the template later) and defaults to ",{"type":39,"tag":53,"props":100,"children":102},{"className":101},[],[103],{"type":48,"value":104},"aws",{"type":48,"value":106}," classic \u002F ",{"type":39,"tag":53,"props":108,"children":110},{"className":109},[],[111],{"type":48,"value":112},"azure-native",{"type":48,"value":114},". The useful reference material from those two skills has been curated into ",{"type":39,"tag":116,"props":117,"children":119},"a",{"href":118},"cloudformation.md",[120],{"type":39,"tag":53,"props":121,"children":123},{"className":122},[],[124],{"type":48,"value":118},{"type":48,"value":126}," and ",{"type":39,"tag":116,"props":128,"children":130},{"href":129},"arm.md",[131],{"type":39,"tag":53,"props":132,"children":134},{"className":133},[],[135],{"type":48,"value":129},{"type":48,"value":137}," in this folder.",{"type":39,"tag":139,"props":140,"children":141},"hr",{},[],{"type":39,"tag":143,"props":144,"children":146},"h2",{"id":145},"plan-adjustment",[147],{"type":48,"value":148},"Plan adjustment",{"type":39,"tag":40,"props":150,"children":151},{},[152],{"type":48,"value":153},"If you already generated a migration plan before loading this skill, review it against the workflow below and update it — the phases here supersede any earlier plan. Communicate the adjusted plan to the user before proceeding.",{"type":39,"tag":143,"props":155,"children":157},{"id":156},"success-criteria",[158],{"type":48,"value":159},"Success criteria",{"type":39,"tag":40,"props":161,"children":162},{},[163],{"type":48,"value":164},"A migration is complete when:",{"type":39,"tag":166,"props":167,"children":168},"ol",{},[169,180,198,216],{"type":39,"tag":170,"props":171,"children":172},"li",{},[173,178],{"type":39,"tag":44,"props":174,"children":175},{},[176],{"type":48,"value":177},"Complete resource coverage",{"type":48,"value":179}," — every discovered resource is imported OR has an annotation explaining why not.",{"type":39,"tag":170,"props":181,"children":182},{},[183,188,190,196],{"type":39,"tag":44,"props":184,"children":185},{},[186],{"type":48,"value":187},"Zero-diff",{"type":48,"value":189}," — ",{"type":39,"tag":53,"props":191,"children":193},{"className":192},[],[194],{"type":48,"value":195},"pulumi preview",{"type":48,"value":197}," shows no changes. This proves the code matches the cloud state exactly.",{"type":39,"tag":170,"props":199,"children":200},{},[201,206,208,214],{"type":39,"tag":44,"props":202,"children":203},{},[204],{"type":48,"value":205},"Progress tracked via the API",{"type":48,"value":207}," — use ",{"type":39,"tag":53,"props":209,"children":211},{"className":210},[],[212],{"type":48,"value":213},"compareTo",{"type":48,"value":215}," and migration annotations so progress is visible in Pulumi Cloud, not just in agent memory.",{"type":39,"tag":170,"props":217,"children":218},{},[219,224],{"type":39,"tag":44,"props":220,"children":221},{},[222],{"type":48,"value":223},"PR as the output",{"type":48,"value":225}," — a pull request with the migrated code and a migration report.",{"type":39,"tag":143,"props":227,"children":229},{"id":228},"the-discovered-stacks-api",[230],{"type":48,"value":231},"THE DISCOVERED-STACKS API",{"type":39,"tag":233,"props":234,"children":236},"h3",{"id":235},"fetching-resources",[237],{"type":48,"value":238},"Fetching resources",{"type":39,"tag":240,"props":241,"children":245},"pre",{"className":242,"code":244,"language":48},[243],"language-text","GET \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fresources?compareTo={targetProject}\u002F{targetStack}\n",[246],{"type":39,"tag":53,"props":247,"children":249},{"__ignoreMap":248},"",[250],{"type":48,"value":244},{"type":39,"tag":40,"props":252,"children":253},{},[254,256,261,263,269,271],{"type":48,"value":255},"Always include ",{"type":39,"tag":53,"props":257,"children":259},{"className":258},[],[260],{"type":48,"value":213},{"type":48,"value":262}," if the target Pulumi stack exists (it may already have state from a previous migration attempt). Returns a list of ",{"type":39,"tag":53,"props":264,"children":266},{"className":265},[],[267],{"type":48,"value":268},"DiscoveredResourceInfo",{"type":48,"value":270}," objects. ",{"type":39,"tag":44,"props":272,"children":273},{},[274],{"type":48,"value":275},"The JSON paths below are exact — verify before consuming:",{"type":39,"tag":277,"props":278,"children":279},"ul",{},[280,296,323,350,369,388,399],{"type":39,"tag":170,"props":281,"children":282},{},[283,289,291],{"type":39,"tag":53,"props":284,"children":286},{"className":285},[],[287],{"type":48,"value":288},"name",{"type":48,"value":290}," — top-level: logical name (CF Logical ID \u002F ARM resource name). ",{"type":39,"tag":44,"props":292,"children":293},{},[294],{"type":48,"value":295},"Use this as the Pulumi resource name.",{"type":39,"tag":170,"props":297,"children":298},{},[299,305,307,313,315,321],{"type":39,"tag":53,"props":300,"children":302},{"className":301},[],[303],{"type":48,"value":304},"originType",{"type":48,"value":306}," — top-level: native cloud type (e.g. ",{"type":39,"tag":53,"props":308,"children":310},{"className":309},[],[311],{"type":48,"value":312},"AWS::S3::Bucket",{"type":48,"value":314},", ",{"type":39,"tag":53,"props":316,"children":318},{"className":317},[],[319],{"type":48,"value":320},"Microsoft.Storage\u002FstorageAccounts",{"type":48,"value":322},")",{"type":39,"tag":170,"props":324,"children":325},{},[326,332,334,340,342,348],{"type":39,"tag":53,"props":327,"children":329},{"className":328},[],[330],{"type":48,"value":331},"providerType",{"type":48,"value":333}," — top-level: mapped Pulumi type token (e.g. ",{"type":39,"tag":53,"props":335,"children":337},{"className":336},[],[338],{"type":48,"value":339},"aws:s3\u002Fbucket:Bucket",{"type":48,"value":341},"). ",{"type":39,"tag":53,"props":343,"children":345},{"className":344},[],[346],{"type":48,"value":347},"null",{"type":48,"value":349}," if unmapped.",{"type":39,"tag":170,"props":351,"children":352},{},[353,359,361,367],{"type":39,"tag":53,"props":354,"children":356},{"className":355},[],[357],{"type":48,"value":358},"resource.inputs.providerId",{"type":48,"value":360}," — physical cloud ID for ",{"type":39,"tag":53,"props":362,"children":364},{"className":363},[],[365],{"type":48,"value":366},"pulumi import",{"type":48,"value":368},".",{"type":39,"tag":170,"props":370,"children":371},{},[372,378,380,386],{"type":39,"tag":53,"props":373,"children":375},{"className":374},[],[376],{"type":48,"value":377},"resource.urn",{"type":48,"value":379}," — the URN to use as ",{"type":39,"tag":53,"props":381,"children":383},{"className":382},[],[384],{"type":48,"value":385},"resourceUrn",{"type":48,"value":387}," in annotation requests (copy verbatim).",{"type":39,"tag":170,"props":389,"children":390},{},[391,397],{"type":39,"tag":53,"props":392,"children":394},{"className":393},[],[395],{"type":48,"value":396},"migrationStatus",{"type":48,"value":398}," — top-level: one of the statuses below.",{"type":39,"tag":170,"props":400,"children":401},{},[402,408],{"type":39,"tag":53,"props":403,"children":405},{"className":404},[],[406],{"type":48,"value":407},"annotation",{"type":48,"value":409}," — top-level: user\u002Fagent annotation if one exists (see Annotations below).",{"type":39,"tag":40,"props":411,"children":412},{},[413,415,421],{"type":48,"value":414},"The ",{"type":39,"tag":53,"props":416,"children":418},{"className":417},[],[419],{"type":48,"value":420},"resource.inputs",{"type":48,"value":422}," object also carries raw cloud-provider data:",{"type":39,"tag":40,"props":424,"children":425},{},[426,431,432,438],{"type":39,"tag":44,"props":427,"children":428},{},[429],{"type":48,"value":430},"For CloudFormation",{"type":48,"value":189},{"type":39,"tag":53,"props":433,"children":435},{"className":434},[],[436],{"type":48,"value":437},"resource.inputs.cloudFormation",{"type":48,"value":439},":",{"type":39,"tag":277,"props":441,"children":442},{},[443,454,472,496],{"type":39,"tag":170,"props":444,"children":445},{},[446,452],{"type":39,"tag":53,"props":447,"children":449},{"className":448},[],[450],{"type":48,"value":451},"physicalResourceId",{"type":48,"value":453}," — the original CF physical ID",{"type":39,"tag":170,"props":455,"children":456},{},[457,463,465,471],{"type":39,"tag":53,"props":458,"children":460},{"className":459},[],[461],{"type":48,"value":462},"resourceType",{"type":48,"value":464}," — the CF type (e.g. ",{"type":39,"tag":53,"props":466,"children":468},{"className":467},[],[469],{"type":48,"value":470},"AWS::IAM::Role",{"type":48,"value":322},{"type":39,"tag":170,"props":473,"children":474},{},[475,481,483,489,490],{"type":39,"tag":53,"props":476,"children":478},{"className":477},[],[479],{"type":48,"value":480},"resourceStatus",{"type":48,"value":482}," — e.g. ",{"type":39,"tag":53,"props":484,"children":486},{"className":485},[],[487],{"type":48,"value":488},"CREATE_COMPLETE",{"type":48,"value":314},{"type":39,"tag":53,"props":491,"children":493},{"className":492},[],[494],{"type":48,"value":495},"DELETE_COMPLETE",{"type":39,"tag":170,"props":497,"children":498},{},[499,505,506,512,513,519,520],{"type":39,"tag":53,"props":500,"children":502},{"className":501},[],[503],{"type":48,"value":504},"driftStatus",{"type":48,"value":189},{"type":39,"tag":53,"props":507,"children":509},{"className":508},[],[510],{"type":48,"value":511},"NOT_CHECKED",{"type":48,"value":314},{"type":39,"tag":53,"props":514,"children":516},{"className":515},[],[517],{"type":48,"value":518},"IN_SYNC",{"type":48,"value":314},{"type":39,"tag":53,"props":521,"children":523},{"className":522},[],[524],{"type":48,"value":525},"DRIFTED",{"type":39,"tag":40,"props":527,"children":528},{},[529,531,537,539,548],{"type":48,"value":530},"For CDK-synthesized CF stacks, ",{"type":39,"tag":53,"props":532,"children":534},{"className":533},[],[535],{"type":48,"value":536},"inputs.cdkPath",{"type":48,"value":538}," is also present — see ",{"type":39,"tag":116,"props":540,"children":541},{"href":118},[542],{"type":39,"tag":53,"props":543,"children":545},{"className":544},[],[546],{"type":48,"value":547},"cloudformation.md §5",{"type":48,"value":549}," for how to use it.",{"type":39,"tag":40,"props":551,"children":552},{},[553,558,559,565,567,573,575,581],{"type":39,"tag":44,"props":554,"children":555},{},[556],{"type":48,"value":557},"For ARM",{"type":48,"value":189},{"type":39,"tag":53,"props":560,"children":562},{"className":561},[],[563],{"type":48,"value":564},"resource.inputs.arm",{"type":48,"value":566},". ARM resources are grouped by resource group, not by\ndeployment, so a resource with no deployment currently backing it (its deployment history\naged out of Azure's retention window, or it was created outside any tracked deployment) is\nstill returned — just as a placeholder, with ",{"type":39,"tag":53,"props":568,"children":570},{"className":569},[],[571],{"type":48,"value":572},"resource.inputs.deploymentName",{"type":48,"value":574}," empty and a\ndifferent ",{"type":39,"tag":53,"props":576,"children":578},{"className":577},[],[579],{"type":48,"value":580},"arm",{"type":48,"value":582}," shape:",{"type":39,"tag":277,"props":584,"children":585},{},[586,648],{"type":39,"tag":170,"props":587,"children":588},{},[589,594,595,600,602,607,609,615,617,623,625,631,632,638,640,646],{"type":39,"tag":44,"props":590,"children":591},{},[592],{"type":48,"value":593},"Deployment-backed",{"type":48,"value":51},{"type":39,"tag":53,"props":596,"children":598},{"className":597},[],[599],{"type":48,"value":572},{"type":48,"value":601}," non-empty) — ",{"type":39,"tag":53,"props":603,"children":605},{"className":604},[],[606],{"type":48,"value":580},{"type":48,"value":608}," is a\ndeployment-operation object: ",{"type":39,"tag":53,"props":610,"children":612},{"className":611},[],[613],{"type":48,"value":614},"properties.targetResource.id",{"type":48,"value":616}," \u002F ",{"type":39,"tag":53,"props":618,"children":620},{"className":619},[],[621],{"type":48,"value":622},".resourceType",{"type":48,"value":624}," \u002F\n",{"type":39,"tag":53,"props":626,"children":628},{"className":627},[],[629],{"type":48,"value":630},".resourceName",{"type":48,"value":314},{"type":39,"tag":53,"props":633,"children":635},{"className":634},[],[636],{"type":48,"value":637},"properties.provisioningState",{"type":48,"value":639}," (e.g. ",{"type":39,"tag":53,"props":641,"children":643},{"className":642},[],[644],{"type":48,"value":645},"Succeeded",{"type":48,"value":647},").",{"type":39,"tag":170,"props":649,"children":650},{},[651,656,657,662,664,669,671,677,678,683,684,690,691,697,698,704,706,712],{"type":39,"tag":44,"props":652,"children":653},{},[654],{"type":48,"value":655},"Placeholder",{"type":48,"value":51},{"type":39,"tag":53,"props":658,"children":660},{"className":659},[],[661],{"type":48,"value":572},{"type":48,"value":663}," empty) — ",{"type":39,"tag":53,"props":665,"children":667},{"className":666},[],[668],{"type":48,"value":580},{"type":48,"value":670}," is the raw Azure\ngeneric-resource object instead: top-level ",{"type":39,"tag":53,"props":672,"children":674},{"className":673},[],[675],{"type":48,"value":676},"id",{"type":48,"value":314},{"type":39,"tag":53,"props":679,"children":681},{"className":680},[],[682],{"type":48,"value":288},{"type":48,"value":314},{"type":39,"tag":53,"props":685,"children":687},{"className":686},[],[688],{"type":48,"value":689},"type",{"type":48,"value":314},{"type":39,"tag":53,"props":692,"children":694},{"className":693},[],[695],{"type":48,"value":696},"location",{"type":48,"value":314},{"type":39,"tag":53,"props":699,"children":701},{"className":700},[],[702],{"type":48,"value":703},"tags",{"type":48,"value":705},".\nNo ",{"type":39,"tag":53,"props":707,"children":709},{"className":708},[],[710],{"type":48,"value":711},"properties.targetResource",{"type":48,"value":713}," — don't look for it.",{"type":39,"tag":40,"props":715,"children":716},{},[717,719,724,726,731],{"type":48,"value":718},"Either way, prefer the top-level ",{"type":39,"tag":53,"props":720,"children":722},{"className":721},[],[723],{"type":48,"value":358},{"type":48,"value":725}," for the import ID (see\nabove) rather than reaching into ",{"type":39,"tag":53,"props":727,"children":729},{"className":728},[],[730],{"type":48,"value":580},{"type":48,"value":732}," — it's already normalized across both shapes.",{"type":39,"tag":233,"props":734,"children":736},{"id":735},"migration-statuses",[737],{"type":48,"value":738},"Migration statuses",{"type":39,"tag":40,"props":740,"children":741},{},[742],{"type":48,"value":743},"Statuses are PascalCase. First match wins:",{"type":39,"tag":166,"props":745,"children":746},{},[747,768,811,837,880,944],{"type":39,"tag":170,"props":748,"children":749},{},[750,759,761,766],{"type":39,"tag":44,"props":751,"children":752},{},[753],{"type":39,"tag":53,"props":754,"children":756},{"className":755},[],[757],{"type":48,"value":758},"Migrated",{"type":48,"value":760}," — the resource was found in the ",{"type":39,"tag":53,"props":762,"children":764},{"className":763},[],[765],{"type":48,"value":213},{"type":48,"value":767}," Pulumi stack. Already under Pulumi management; skip.",{"type":39,"tag":170,"props":769,"children":770},{},[771,780,781,786,787,793,795,801,803,809],{"type":39,"tag":44,"props":772,"children":773},{},[774],{"type":39,"tag":53,"props":775,"children":777},{"className":776},[],[778],{"type":48,"value":779},"Ready",{"type":48,"value":189},{"type":39,"tag":53,"props":782,"children":784},{"className":783},[],[785],{"type":48,"value":331},{"type":48,"value":126},{"type":39,"tag":53,"props":788,"children":790},{"className":789},[],[791],{"type":48,"value":792},"providerId",{"type":48,"value":794}," are set and the scanner confirmed the resource exists. Import with ",{"type":39,"tag":53,"props":796,"children":798},{"className":797},[],[799],{"type":48,"value":800},"pulumi import \u003CproviderType> \u003Cname> \u003CproviderId> --generate-code --out \u003Cfile>.ts",{"type":48,"value":802}," (NEVER without ",{"type":39,"tag":53,"props":804,"children":806},{"className":805},[],[807],{"type":48,"value":808},"--generate-code --out",{"type":48,"value":810}," — see Phase 4).",{"type":39,"tag":170,"props":812,"children":813},{},[814,823,824,829,830,835],{"type":39,"tag":44,"props":815,"children":816},{},[817],{"type":39,"tag":53,"props":818,"children":820},{"className":819},[],[821],{"type":48,"value":822},"NotFound",{"type":48,"value":189},{"type":39,"tag":53,"props":825,"children":827},{"className":826},[],[828],{"type":48,"value":331},{"type":48,"value":126},{"type":39,"tag":53,"props":831,"children":833},{"className":832},[],[834],{"type":48,"value":792},{"type":48,"value":836}," are set, but the scanner could not confirm the resource's current state. May be deleted, mapping may be imperfect, or scanner hit a gap. Verify before importing.",{"type":39,"tag":170,"props":838,"children":839},{},[840,849,851,857,858,864,865,871,872,878],{"type":39,"tag":44,"props":841,"children":842},{},[843],{"type":39,"tag":53,"props":844,"children":846},{"className":845},[],[847],{"type":48,"value":848},"NotApplicable",{"type":48,"value":850}," — container or wrapper types (",{"type":39,"tag":53,"props":852,"children":854},{"className":853},[],[855],{"type":48,"value":856},"AWS::CloudFormation::Stack",{"type":48,"value":314},{"type":39,"tag":53,"props":859,"children":861},{"className":860},[],[862],{"type":48,"value":863},"Microsoft.Resources\u002Fdeployments",{"type":48,"value":314},{"type":39,"tag":53,"props":866,"children":868},{"className":867},[],[869],{"type":48,"value":870},"Microsoft.Resources\u002FresourceGroups",{"type":48,"value":314},{"type":39,"tag":53,"props":873,"children":875},{"className":874},[],[876],{"type":48,"value":877},"pulumi:providers:*",{"type":48,"value":879},") are not individually migratable. Skip silently.",{"type":39,"tag":170,"props":881,"children":882},{},[883,892,893,898,900,905,907],{"type":39,"tag":44,"props":884,"children":885},{},[886],{"type":39,"tag":53,"props":887,"children":889},{"className":888},[],[890],{"type":48,"value":891},"NoMatch",{"type":48,"value":189},{"type":39,"tag":53,"props":894,"children":896},{"className":895},[],[897],{"type":48,"value":331},{"type":48,"value":899}," is ",{"type":39,"tag":53,"props":901,"children":903},{"className":902},[],[904],{"type":48,"value":347},{"type":48,"value":906},". No mapping found. Common examples:\n",{"type":39,"tag":277,"props":908,"children":909},{},[910,923],{"type":39,"tag":170,"props":911,"children":912},{},[913,915,921],{"type":48,"value":914},"CF Custom Resources (e.g. ",{"type":39,"tag":53,"props":916,"children":918},{"className":917},[],[919],{"type":48,"value":920},"Custom::VpcRestrictDefaultSG",{"type":48,"value":922},") — no direct Pulumi equivalent.",{"type":39,"tag":170,"props":924,"children":925},{},[926,928,934,936,942],{"type":48,"value":927},"Inline policies — ",{"type":39,"tag":53,"props":929,"children":931},{"className":930},[],[932],{"type":48,"value":933},"AWS::IAM::Policy",{"type":48,"value":935}," modeled as an inline property of ",{"type":39,"tag":53,"props":937,"children":939},{"className":938},[],[940],{"type":48,"value":941},"aws:iam\u002Frole:Role",{"type":48,"value":943},". Once the parent Role is migrated, annotate the policy as migrated.",{"type":39,"tag":170,"props":945,"children":946},{},[947,956,958,963],{"type":39,"tag":44,"props":948,"children":949},{},[950],{"type":39,"tag":53,"props":951,"children":953},{"className":952},[],[954],{"type":48,"value":955},"PulumiOnly",{"type":48,"value":957}," — exists in the ",{"type":39,"tag":53,"props":959,"children":961},{"className":960},[],[962],{"type":48,"value":213},{"type":48,"value":964}," stack with no discovered counterpart, or those created to migrate NoMatch resources. Surface to user.",{"type":39,"tag":40,"props":966,"children":967},{},[968,970,976],{"type":48,"value":969},"Resources with ",{"type":39,"tag":53,"props":971,"children":973},{"className":972},[],[974],{"type":48,"value":975},"annotation.statusOverride",{"type":48,"value":977}," should be treated as resolved per the override, even if the computed status disagrees.",{"type":39,"tag":233,"props":979,"children":981},{"id":980},"annotations",[982],{"type":48,"value":983},"Annotations",{"type":39,"tag":240,"props":985,"children":988},{"className":986,"code":987,"language":48},[243],"PUT  \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fmigration\nDELETE \u002Fapi\u002Fpreview\u002Finsights\u002F{orgName}\u002Fdiscovered-stacks\u002F{projectName}\u002F{stackName}\u002Fmigration?resourceUrn={urn}\n",[989],{"type":39,"tag":53,"props":990,"children":991},{"__ignoreMap":248},[992],{"type":48,"value":987},{"type":39,"tag":40,"props":994,"children":995},{},[996],{"type":48,"value":997},"PUT body:",{"type":39,"tag":240,"props":999,"children":1003},{"className":1000,"code":1001,"language":1002,"meta":248,"style":248},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"resourceUrn\": \"\u003Ccopy verbatim from resource.urn in the list response>\",\n  \"note\": \"explanation of what happened\",\n  \"statusOverride\": \"Migrated\" | \"\",\n  \"linkedResourceUrn\": \"\u003Coptional: URN of the Pulumi resource paired 1:1 with this origin>\"\n}\n","json",[1004],{"type":39,"tag":53,"props":1005,"children":1006},{"__ignoreMap":248},[1007,1019,1062,1100,1147,1182],{"type":39,"tag":1008,"props":1009,"children":1012},"span",{"class":1010,"line":1011},"line",1,[1013],{"type":39,"tag":1008,"props":1014,"children":1016},{"style":1015},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[1017],{"type":48,"value":1018},"{\n",{"type":39,"tag":1008,"props":1020,"children":1022},{"class":1010,"line":1021},2,[1023,1028,1033,1038,1042,1047,1053,1057],{"type":39,"tag":1008,"props":1024,"children":1025},{"style":1015},[1026],{"type":48,"value":1027},"  \"",{"type":39,"tag":1008,"props":1029,"children":1031},{"style":1030},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[1032],{"type":48,"value":385},{"type":39,"tag":1008,"props":1034,"children":1035},{"style":1015},[1036],{"type":48,"value":1037},"\"",{"type":39,"tag":1008,"props":1039,"children":1040},{"style":1015},[1041],{"type":48,"value":439},{"type":39,"tag":1008,"props":1043,"children":1044},{"style":1015},[1045],{"type":48,"value":1046}," \"",{"type":39,"tag":1008,"props":1048,"children":1050},{"style":1049},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[1051],{"type":48,"value":1052},"\u003Ccopy verbatim from resource.urn in the list response>",{"type":39,"tag":1008,"props":1054,"children":1055},{"style":1015},[1056],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1058,"children":1059},{"style":1015},[1060],{"type":48,"value":1061},",\n",{"type":39,"tag":1008,"props":1063,"children":1065},{"class":1010,"line":1064},3,[1066,1070,1075,1079,1083,1087,1092,1096],{"type":39,"tag":1008,"props":1067,"children":1068},{"style":1015},[1069],{"type":48,"value":1027},{"type":39,"tag":1008,"props":1071,"children":1072},{"style":1030},[1073],{"type":48,"value":1074},"note",{"type":39,"tag":1008,"props":1076,"children":1077},{"style":1015},[1078],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1080,"children":1081},{"style":1015},[1082],{"type":48,"value":439},{"type":39,"tag":1008,"props":1084,"children":1085},{"style":1015},[1086],{"type":48,"value":1046},{"type":39,"tag":1008,"props":1088,"children":1089},{"style":1049},[1090],{"type":48,"value":1091},"explanation of what happened",{"type":39,"tag":1008,"props":1093,"children":1094},{"style":1015},[1095],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1097,"children":1098},{"style":1015},[1099],{"type":48,"value":1061},{"type":39,"tag":1008,"props":1101,"children":1102},{"class":1010,"line":27},[1103,1107,1112,1116,1120,1124,1128,1132,1138,1143],{"type":39,"tag":1008,"props":1104,"children":1105},{"style":1015},[1106],{"type":48,"value":1027},{"type":39,"tag":1008,"props":1108,"children":1109},{"style":1030},[1110],{"type":48,"value":1111},"statusOverride",{"type":39,"tag":1008,"props":1113,"children":1114},{"style":1015},[1115],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1117,"children":1118},{"style":1015},[1119],{"type":48,"value":439},{"type":39,"tag":1008,"props":1121,"children":1122},{"style":1015},[1123],{"type":48,"value":1046},{"type":39,"tag":1008,"props":1125,"children":1126},{"style":1049},[1127],{"type":48,"value":758},{"type":39,"tag":1008,"props":1129,"children":1130},{"style":1015},[1131],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1133,"children":1135},{"style":1134},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[1136],{"type":48,"value":1137}," | ",{"type":39,"tag":1008,"props":1139,"children":1140},{"style":1015},[1141],{"type":48,"value":1142},"\"\"",{"type":39,"tag":1008,"props":1144,"children":1145},{"style":1015},[1146],{"type":48,"value":1061},{"type":39,"tag":1008,"props":1148,"children":1150},{"class":1010,"line":1149},5,[1151,1155,1160,1164,1168,1172,1177],{"type":39,"tag":1008,"props":1152,"children":1153},{"style":1015},[1154],{"type":48,"value":1027},{"type":39,"tag":1008,"props":1156,"children":1157},{"style":1030},[1158],{"type":48,"value":1159},"linkedResourceUrn",{"type":39,"tag":1008,"props":1161,"children":1162},{"style":1015},[1163],{"type":48,"value":1037},{"type":39,"tag":1008,"props":1165,"children":1166},{"style":1015},[1167],{"type":48,"value":439},{"type":39,"tag":1008,"props":1169,"children":1170},{"style":1015},[1171],{"type":48,"value":1046},{"type":39,"tag":1008,"props":1173,"children":1174},{"style":1049},[1175],{"type":48,"value":1176},"\u003Coptional: URN of the Pulumi resource paired 1:1 with this origin>",{"type":39,"tag":1008,"props":1178,"children":1179},{"style":1015},[1180],{"type":48,"value":1181},"\"\n",{"type":39,"tag":1008,"props":1183,"children":1185},{"class":1010,"line":1184},6,[1186],{"type":39,"tag":1008,"props":1187,"children":1188},{"style":1015},[1189],{"type":48,"value":1190},"}\n",{"type":39,"tag":40,"props":1192,"children":1193},{},[1194,1196,1201,1202,1207,1209,1214,1216,1221,1223,1228],{"type":48,"value":1195},"Use the Pulumi Cloud API for all annotation requests. At least one of ",{"type":39,"tag":53,"props":1197,"children":1199},{"className":1198},[],[1200],{"type":48,"value":1074},{"type":48,"value":80},{"type":39,"tag":53,"props":1203,"children":1205},{"className":1204},[],[1206],{"type":48,"value":1111},{"type":48,"value":1208}," must be non-empty. Omit ",{"type":39,"tag":53,"props":1210,"children":1212},{"className":1211},[],[1213],{"type":48,"value":1111},{"type":48,"value":1215}," entirely (do not send ",{"type":39,"tag":53,"props":1217,"children":1219},{"className":1218},[],[1220],{"type":48,"value":347},{"type":48,"value":1222},") when updating only the note. The DELETE endpoint clears both the note and any ",{"type":39,"tag":53,"props":1224,"children":1226},{"className":1225},[],[1227],{"type":48,"value":1111},{"type":48,"value":368},{"type":39,"tag":40,"props":1230,"children":1231},{},[1232],{"type":48,"value":1233},"Use annotations to:",{"type":39,"tag":277,"props":1235,"children":1236},{},[1237,1249,1275,1321,1326],{"type":39,"tag":170,"props":1238,"children":1239},{},[1240,1242,1247],{"type":48,"value":1241},"Flag deleted resources as ",{"type":39,"tag":53,"props":1243,"children":1245},{"className":1244},[],[1246],{"type":48,"value":758},{"type":48,"value":1248}," with a note explaining they no longer exist",{"type":39,"tag":170,"props":1250,"children":1251},{},[1252,1254,1259,1261,1266,1268,1273],{"type":48,"value":1253},"Flag inline\u002Fchild resources covered by a parent's migration as ",{"type":39,"tag":53,"props":1255,"children":1257},{"className":1256},[],[1258],{"type":48,"value":758},{"type":48,"value":1260}," with a note naming the parent — ",{"type":39,"tag":44,"props":1262,"children":1263},{},[1264],{"type":48,"value":1265},"do not",{"type":48,"value":1267}," use ",{"type":39,"tag":53,"props":1269,"children":1271},{"className":1270},[],[1272],{"type":48,"value":1159},{"type":48,"value":1274}," here (it's a 1:many relationship and the UI only merges 1:1 pairs)",{"type":39,"tag":170,"props":1276,"children":1277},{},[1278,1280,1285,1286,1291,1293,1298,1300,1306,1308,1313,1315,1320],{"type":48,"value":1279},"Bridge a ",{"type":39,"tag":53,"props":1281,"children":1283},{"className":1282},[],[1284],{"type":48,"value":822},{"type":48,"value":80},{"type":39,"tag":53,"props":1287,"children":1289},{"className":1288},[],[1290],{"type":48,"value":891},{"type":48,"value":1292}," origin to its ",{"type":39,"tag":53,"props":1294,"children":1296},{"className":1295},[],[1297],{"type":48,"value":955},{"type":48,"value":1299}," counterpart after a corrected mapping (",{"type":39,"tag":53,"props":1301,"children":1303},{"className":1302},[],[1304],{"type":48,"value":1305},"statusOverride=Migrated",{"type":48,"value":1307}," + ",{"type":39,"tag":53,"props":1309,"children":1311},{"className":1310},[],[1312],{"type":48,"value":1159},{"type":48,"value":1314}," → the PulumiOnly URN). This is the only valid use of ",{"type":39,"tag":53,"props":1316,"children":1318},{"className":1317},[],[1319],{"type":48,"value":1159},{"type":48,"value":368},{"type":39,"tag":170,"props":1322,"children":1323},{},[1324],{"type":48,"value":1325},"Leave notes explaining blockers or manual steps taken",{"type":39,"tag":170,"props":1327,"children":1328},{},[1329],{"type":48,"value":1330},"Track decisions for resources the automatic classifier can't resolve",{"type":39,"tag":40,"props":1332,"children":1333},{},[1334],{"type":48,"value":1335},"The annotation endpoint is the shared place to track migration progress — always read existing annotations before acting on a resource, and respect overrides left by the user.",{"type":39,"tag":40,"props":1337,"children":1338},{},[1339,1340,1345,1347,1352],{"type":48,"value":414},{"type":39,"tag":53,"props":1341,"children":1343},{"className":1342},[],[1344],{"type":48,"value":1074},{"type":48,"value":1346}," field is user-authored context. Treat it as a ",{"type":39,"tag":44,"props":1348,"children":1349},{},[1350],{"type":48,"value":1351},"high-priority instruction",{"type":48,"value":1353}," about that specific resource. Common uses: naming preferences, import ID hints, resources to skip, or special handling instructions. Notes reach the agent through two channels:",{"type":39,"tag":166,"props":1355,"children":1356},{},[1357,1382],{"type":39,"tag":170,"props":1358,"children":1359},{},[1360,1365,1367,1376,1380],{"type":39,"tag":44,"props":1361,"children":1362},{},[1363],{"type":48,"value":1364},"Starting prompt",{"type":48,"value":1366}," — when the user kicks off a migration task, any note on a selected resource is appended to that resource's line:",{"type":39,"tag":240,"props":1368,"children":1371},{"className":1369,"code":1370,"language":48},[243],"- aws:s3\u002Fbucket:Bucket \"my-bucket\" (provider ID: my-bucket-prod) — note: use logical name \"appBucket\" in code\n",[1372],{"type":39,"tag":53,"props":1373,"children":1374},{"__ignoreMap":248},[1375],{"type":48,"value":1370},{"type":39,"tag":1377,"props":1378,"children":1379},"br",{},[],{"type":48,"value":1381},"Read these before calling the API.",{"type":39,"tag":170,"props":1383,"children":1384},{},[1385,1390,1392,1398,1400,1405,1407,1413,1415,1420],{"type":39,"tag":44,"props":1386,"children":1387},{},[1388],{"type":48,"value":1389},"API response",{"type":48,"value":1391}," — the ",{"type":39,"tag":53,"props":1393,"children":1395},{"className":1394},[],[1396],{"type":48,"value":1397},"annotation.note",{"type":48,"value":1399}," field on each ",{"type":39,"tag":53,"props":1401,"children":1403},{"className":1402},[],[1404],{"type":48,"value":268},{"type":48,"value":1406}," when you call ",{"type":39,"tag":53,"props":1408,"children":1410},{"className":1409},[],[1411],{"type":48,"value":1412},"GET ...\u002Fresources",{"type":48,"value":1414},". The ",{"type":39,"tag":53,"props":1416,"children":1418},{"className":1417},[],[1419],{"type":48,"value":407},{"type":48,"value":1421}," object is omitted entirely when no annotation has been set.",{"type":39,"tag":139,"props":1423,"children":1424},{},[],{"type":39,"tag":143,"props":1426,"children":1428},{"id":1427},"migration-workflow",[1429],{"type":48,"value":1430},"MIGRATION WORKFLOW",{"type":39,"tag":233,"props":1432,"children":1434},{"id":1433},"phase-0-preconditions-and-scoping",[1435],{"type":48,"value":1436},"Phase 0 — Preconditions and scoping",{"type":39,"tag":40,"props":1438,"children":1439},{},[1440,1442,1447,1449,1454],{"type":48,"value":1441},"Before any tool call, gather and confirm ",{"type":39,"tag":44,"props":1443,"children":1444},{},[1445],{"type":48,"value":1446},"all",{"type":48,"value":1448}," of the following. If anything is missing, ",{"type":39,"tag":44,"props":1450,"children":1451},{},[1452],{"type":48,"value":1453},"ask",{"type":48,"value":1455}," — don't proceed with a guess.",{"type":39,"tag":40,"props":1457,"children":1458},{},[1459],{"type":39,"tag":44,"props":1460,"children":1461},{},[1462],{"type":48,"value":1463},"Source (the discovered stack):",{"type":39,"tag":277,"props":1465,"children":1466},{},[1467,1479,1491,1504],{"type":39,"tag":170,"props":1468,"children":1469},{},[1470,1472,1478],{"type":48,"value":1471},"Org name (e.g. ",{"type":39,"tag":53,"props":1473,"children":1475},{"className":1474},[],[1476],{"type":48,"value":1477},"pulumi_local",{"type":48,"value":322},{"type":39,"tag":170,"props":1480,"children":1481},{},[1482,1484,1490],{"type":48,"value":1483},"Discovered project name (e.g. ",{"type":39,"tag":53,"props":1485,"children":1487},{"className":1486},[],[1488],{"type":48,"value":1489},"AcmeCdkExampleStack",{"type":48,"value":322},{"type":39,"tag":170,"props":1492,"children":1493},{},[1494,1496,1502],{"type":48,"value":1495},"Discovered stack name (e.g. ",{"type":39,"tag":53,"props":1497,"children":1499},{"className":1498},[],[1500],{"type":48,"value":1501},"dev-sandbox-disc_us-west-2__Dev",{"type":48,"value":1503},") — this is the scanner-generated name, usually encoding account + region + CF\u002FARM stack name.",{"type":39,"tag":170,"props":1505,"children":1506},{},[1507],{"type":48,"value":1508},"Region (confirm even if the stack name suggests it).",{"type":39,"tag":40,"props":1510,"children":1511},{},[1512],{"type":39,"tag":44,"props":1513,"children":1514},{},[1515],{"type":48,"value":1516},"Target (where the Pulumi code and state will live):",{"type":39,"tag":277,"props":1518,"children":1519},{},[1520,1530,1540,1557],{"type":39,"tag":170,"props":1521,"children":1522},{},[1523,1528],{"type":39,"tag":44,"props":1524,"children":1525},{},[1526],{"type":48,"value":1527},"Target git repo URL",{"type":48,"value":1529}," — ask the user. All work happens inside this repo from the start.",{"type":39,"tag":170,"props":1531,"children":1532},{},[1533,1538],{"type":39,"tag":44,"props":1534,"children":1535},{},[1536],{"type":48,"value":1537},"Subfolder",{"type":48,"value":1539}," (optional) — ask if the user has a preference; default to repo root.",{"type":39,"tag":170,"props":1541,"children":1542},{},[1543,1548,1550,1555],{"type":39,"tag":44,"props":1544,"children":1545},{},[1546],{"type":48,"value":1547},"Target project + stack names",{"type":48,"value":1549}," — ask the user, don't invent. If the stack already exists, use ",{"type":39,"tag":53,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":48,"value":213},{"type":48,"value":1556}," in Phase 1; if not, create it in Phase 2.",{"type":39,"tag":170,"props":1558,"children":1559},{},[1560,1565],{"type":39,"tag":44,"props":1561,"children":1562},{},[1563],{"type":48,"value":1564},"Target language",{"type":48,"value":1566}," — TypeScript default.",{"type":39,"tag":40,"props":1568,"children":1569},{},[1570,1575],{"type":39,"tag":44,"props":1571,"children":1572},{},[1573],{"type":48,"value":1574},"Refactor preferences",{"type":48,"value":1576}," (for Phase 7):",{"type":39,"tag":277,"props":1578,"children":1579},{},[1580,1599,1611],{"type":39,"tag":170,"props":1581,"children":1582},{},[1583,1585,1590,1592,1597],{"type":48,"value":1584},"Does the user have the ",{"type":39,"tag":44,"props":1586,"children":1587},{},[1588],{"type":48,"value":1589},"original source code",{"type":48,"value":1591}," (CDK repo, Bicep project, Terraform modules)? If yes, path or URL. ",{"type":39,"tag":44,"props":1593,"children":1594},{},[1595],{"type":48,"value":1596},"This is the primary structural reference for Phase 7",{"type":48,"value":1598}," — the refactored Pulumi code will draw on its component boundaries, file layout, and naming conventions as a guide, adapted to what the import model actually produced.",{"type":39,"tag":170,"props":1600,"children":1601},{},[1602,1604,1609],{"type":48,"value":1603},"Does the user have a ",{"type":39,"tag":44,"props":1605,"children":1606},{},[1607],{"type":48,"value":1608},"preferred program layout",{"type":48,"value":1610}," for the Pulumi output? (e.g. \"one file per service\", \"match my existing repo shape\", \"I don't care\")",{"type":39,"tag":170,"props":1612,"children":1613},{},[1614],{"type":48,"value":1615},"Does the user want Phase 7 at all, or stop after zero-diff (Phase 6)?",{"type":39,"tag":40,"props":1617,"children":1618},{},[1619],{"type":39,"tag":44,"props":1620,"children":1621},{},[1622],{"type":48,"value":1623},"Credentials:",{"type":39,"tag":277,"props":1625,"children":1626},{},[1627],{"type":39,"tag":170,"props":1628,"children":1629},{},[1630,1632,1641,1642,1651],{"type":48,"value":1631},"ESC environment for cloud credentials (ask if not given; never invent). ESC is preferred — see ",{"type":39,"tag":116,"props":1633,"children":1634},{"href":118},[1635],{"type":39,"tag":53,"props":1636,"children":1638},{"className":1637},[],[1639],{"type":48,"value":1640},"cloudformation.md §1",{"type":48,"value":80},{"type":39,"tag":116,"props":1643,"children":1644},{"href":129},[1645],{"type":39,"tag":53,"props":1646,"children":1648},{"className":1647},[],[1649],{"type":48,"value":1650},"arm.md §1",{"type":48,"value":368},{"type":39,"tag":40,"props":1653,"children":1654},{},[1655,1660],{"type":39,"tag":44,"props":1656,"children":1657},{},[1658],{"type":48,"value":1659},"Don't start Phase 1 until all of the above are confirmed.",{"type":48,"value":1661}," Summarize the plan back to the user and wait for approval.",{"type":39,"tag":233,"props":1663,"children":1665},{"id":1664},"phase-1-resource-fetch-and-triage",[1666],{"type":48,"value":1667},"Phase 1 — Resource fetch and triage",{"type":39,"tag":40,"props":1669,"children":1670},{},[1671],{"type":48,"value":1672},"Start here every time, even when resuming an existing migration. The API + any existing annotations are the source of truth for what's been done so far. If the target repo already has Pulumi code, read it — it tells you the conventions, existing resources, and how far a previous attempt got.",{"type":39,"tag":166,"props":1674,"children":1675},{},[1676,1730,1746,1764],{"type":39,"tag":170,"props":1677,"children":1678},{},[1679,1681,1686,1688],{"type":48,"value":1680},"Fetch discovered resources: ",{"type":39,"tag":53,"props":1682,"children":1684},{"className":1683},[],[1685],{"type":48,"value":58},{"type":48,"value":1687},".\n",{"type":39,"tag":277,"props":1689,"children":1690},{},[1691,1708],{"type":39,"tag":170,"props":1692,"children":1693},{},[1694,1699,1701,1707],{"type":39,"tag":44,"props":1695,"children":1696},{},[1697],{"type":48,"value":1698},"Target stack exists",{"type":48,"value":1700}," (resumed migration): append ",{"type":39,"tag":53,"props":1702,"children":1704},{"className":1703},[],[1705],{"type":48,"value":1706},"?compareTo=\u003CtargetProject>\u002F\u003CtargetStack>",{"type":48,"value":368},{"type":39,"tag":170,"props":1709,"children":1710},{},[1711,1716,1718,1728],{"type":39,"tag":44,"props":1712,"children":1713},{},[1714],{"type":48,"value":1715},"Target stack does not exist",{"type":48,"value":1717}," (greenfield): ",{"type":39,"tag":44,"props":1719,"children":1720},{},[1721,1723],{"type":48,"value":1722},"omit ",{"type":39,"tag":53,"props":1724,"children":1726},{"className":1725},[],[1727],{"type":48,"value":213},{"type":48,"value":1729}," — the API returns 404 if the target stack isn't found. After Phase 2 creates the stack, subsequent calls can include it.",{"type":39,"tag":170,"props":1731,"children":1732},{},[1733,1738,1739,1745],{"type":39,"tag":44,"props":1734,"children":1735},{},[1736],{"type":48,"value":1737},"Save the response to disk",{"type":48,"value":189},{"type":39,"tag":53,"props":1740,"children":1742},{"className":1741},[],[1743],{"type":48,"value":1744},".\u002F.migration\u002Fresources-baseline.json",{"type":48,"value":368},{"type":39,"tag":170,"props":1747,"children":1748},{},[1749,1754,1756,1762],{"type":39,"tag":44,"props":1750,"children":1751},{},[1752],{"type":48,"value":1753},"Run triage",{"type":48,"value":1755},": ",{"type":39,"tag":53,"props":1757,"children":1759},{"className":1758},[],[1760],{"type":48,"value":1761},"python3 \u003Cskill-base-dir>\u002Fscripts\u002Ftriage.py .migration\u002Fresources-baseline.json",{"type":48,"value":1763}," — prints status counts (accounting for annotation overrides) and a per-resource table.",{"type":39,"tag":170,"props":1765,"children":1766},{},[1767,1769],{"type":48,"value":1768},"Present the plan to the user:\n",{"type":39,"tag":62,"props":1770,"children":1771},{},[1772],{"type":39,"tag":40,"props":1773,"children":1774},{},[1775],{"type":48,"value":1776},"\"Found N resources. A already Migrated, M Ready, K NotFound, J NoMatch, L non-migratable containers. I'll import Ready first, then verify NotFound, then triage NoMatch with you. Sound good?\"",{"type":39,"tag":40,"props":1778,"children":1779},{},[1780],{"type":48,"value":1781},"Get confirmation before writing any code.",{"type":39,"tag":233,"props":1783,"children":1785},{"id":1784},"phase-2-target-repo-and-pulumi-stack-setup",[1786],{"type":48,"value":1787},"Phase 2 — Target repo and Pulumi stack setup",{"type":39,"tag":166,"props":1789,"children":1790},{},[1791,1801,1821,1841],{"type":39,"tag":170,"props":1792,"children":1793},{},[1794,1799],{"type":39,"tag":44,"props":1795,"children":1796},{},[1797],{"type":48,"value":1798},"Clone the target git repo",{"type":48,"value":1800}," (from Phase 0) and work inside it for all subsequent phases. If the repo already has code, read it to understand existing conventions and resources before adding new ones.",{"type":39,"tag":170,"props":1802,"children":1803},{},[1804,1806],{"type":48,"value":1805},"If the target stack already exists (Phase 0 check), select it. Otherwise:\n",{"type":39,"tag":277,"props":1807,"children":1808},{},[1809],{"type":39,"tag":170,"props":1810,"children":1811},{},[1812,1814,1820],{"type":48,"value":1813},"Create the Pulumi project: ",{"type":39,"tag":53,"props":1815,"children":1817},{"className":1816},[],[1818],{"type":48,"value":1819},"pulumi new \u003Clanguage> --name \u003Cproject> --stack \u003Corg>\u002F\u003Cproject>\u002F\u003Cstack> --yes",{"type":48,"value":368},{"type":39,"tag":170,"props":1822,"children":1823},{},[1824,1826,1832,1834,1840],{"type":48,"value":1825},"Set provider config: ",{"type":39,"tag":53,"props":1827,"children":1829},{"className":1828},[],[1830],{"type":48,"value":1831},"pulumi config set aws:region \u003Cr>",{"type":48,"value":1833}," (or ",{"type":39,"tag":53,"props":1835,"children":1837},{"className":1836},[],[1838],{"type":48,"value":1839},"azure-native:location",{"type":48,"value":647},{"type":39,"tag":170,"props":1842,"children":1843},{},[1844],{"type":48,"value":1845},"Link the ESC environment if provided.",{"type":39,"tag":40,"props":1847,"children":1848},{},[1849],{"type":39,"tag":44,"props":1850,"children":1851},{},[1852,1854,1860],{"type":48,"value":1853},"No empty ",{"type":39,"tag":53,"props":1855,"children":1857},{"className":1856},[],[1858],{"type":48,"value":1859},"pulumi up",{"type":48,"value":1861}," needed.",{"type":39,"tag":62,"props":1863,"children":1864},{},[1865],{"type":39,"tag":40,"props":1866,"children":1867},{},[1868,1870,1879,1880,1889],{"type":48,"value":1869},"Concrete commands for project + stack setup, region config, and provider install: ",{"type":39,"tag":116,"props":1871,"children":1872},{"href":118},[1873],{"type":39,"tag":53,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":48,"value":1878},"cloudformation.md §2",{"type":48,"value":80},{"type":39,"tag":116,"props":1881,"children":1882},{"href":129},[1883],{"type":39,"tag":53,"props":1884,"children":1886},{"className":1885},[],[1887],{"type":48,"value":1888},"arm.md §2",{"type":48,"value":368},{"type":39,"tag":233,"props":1891,"children":1893},{"id":1892},"phase-3-build-the-import-file",[1894],{"type":48,"value":1895},"Phase 3 — Build the import file",{"type":39,"tag":40,"props":1897,"children":1898},{},[1899,1901,1907,1909,1914,1916,1921,1923,1928],{"type":48,"value":1900},"Generate the import file: ",{"type":39,"tag":53,"props":1902,"children":1904},{"className":1903},[],[1905],{"type":48,"value":1906},"python3 \u003Cskill-base-dir>\u002Fscripts\u002Fbuild_import.py .migration\u002Fresources-baseline.json .migration\u002Fimport.json",{"type":48,"value":1908},". This filters Ready\u002FNotFound resources (excluding already-annotated ones) and maps API fields to the Pulumi import format (",{"type":39,"tag":53,"props":1910,"children":1912},{"className":1911},[],[1913],{"type":48,"value":689},{"type":48,"value":1915}," ← providerType, ",{"type":39,"tag":53,"props":1917,"children":1919},{"className":1918},[],[1920],{"type":48,"value":288},{"type":48,"value":1922}," ← name, ",{"type":39,"tag":53,"props":1924,"children":1926},{"className":1925},[],[1927],{"type":48,"value":676},{"type":48,"value":1929}," ← resource.inputs.providerId).",{"type":39,"tag":233,"props":1931,"children":1933},{"id":1932},"phase-4-import",[1934],{"type":48,"value":1935},"Phase 4 — Import",{"type":39,"tag":40,"props":1937,"children":1938},{},[1939,1941,1947],{"type":48,"value":1940},"Using the ",{"type":39,"tag":53,"props":1942,"children":1944},{"className":1943},[],[1945],{"type":48,"value":1946},"import.json",{"type":48,"value":1948}," from Phase 3.",{"type":39,"tag":40,"props":1950,"children":1951},{},[1952,1962,1964,1969],{"type":39,"tag":44,"props":1953,"children":1954},{},[1955,1957],{"type":48,"value":1956},"Always use ",{"type":39,"tag":53,"props":1958,"children":1960},{"className":1959},[],[1961],{"type":48,"value":808},{"type":48,"value":1963}," — without it, resources land in state with no code, breaking ",{"type":39,"tag":53,"props":1965,"children":1967},{"className":1966},[],[1968],{"type":48,"value":195},{"type":48,"value":368},{"type":39,"tag":240,"props":1971,"children":1974},{"className":1972,"code":1973,"language":48},[243],"pulumi import --file import.json --generate-code --out batch.\u003Cext>\n# then: append generated code into the main program file and delete the batch file\n",[1975],{"type":39,"tag":53,"props":1976,"children":1977},{"__ignoreMap":248},[1978],{"type":48,"value":1973},{"type":39,"tag":40,"props":1980,"children":1981},{},[1982,1987,1989,1995],{"type":39,"tag":44,"props":1983,"children":1984},{},[1985],{"type":48,"value":1986},"Per-batch loop: import → preview → commit → annotate.",{"type":48,"value":1988}," Aim for ~20 resources per batch. For CDK stacks, batch by ",{"type":39,"tag":53,"props":1990,"children":1992},{"className":1991},[],[1993],{"type":48,"value":1994},"cdkPath",{"type":48,"value":1996}," top-level group; otherwise batch by resource type prefix.",{"type":39,"tag":166,"props":1998,"children":1999},{},[2000,2010,2023,2033],{"type":39,"tag":170,"props":2001,"children":2002},{},[2003,2008],{"type":39,"tag":44,"props":2004,"children":2005},{},[2006],{"type":48,"value":2007},"Import",{"type":48,"value":2009}," the batch.",{"type":39,"tag":170,"props":2011,"children":2012},{},[2013,2021],{"type":39,"tag":44,"props":2014,"children":2015},{},[2016],{"type":39,"tag":53,"props":2017,"children":2019},{"className":2018},[],[2020],{"type":48,"value":195},{"type":48,"value":2022}," — zero diff required. Fix any diffs before moving on.",{"type":39,"tag":170,"props":2024,"children":2025},{},[2026,2031],{"type":39,"tag":44,"props":2027,"children":2028},{},[2029],{"type":48,"value":2030},"Commit",{"type":48,"value":2032}," the program changes to a branch.",{"type":39,"tag":170,"props":2034,"children":2035},{},[2036,2041,2043,2049,2051,2061],{"type":39,"tag":44,"props":2037,"children":2038},{},[2039],{"type":48,"value":2040},"Annotate",{"type":48,"value":2042}," each imported resource — ",{"type":39,"tag":53,"props":2044,"children":2046},{"className":2045},[],[2047],{"type":48,"value":2048},"PUT ...\u002Fmigration",{"type":48,"value":2050}," with note and ",{"type":39,"tag":44,"props":2052,"children":2053},{},[2054,2056],{"type":48,"value":2055},"no ",{"type":39,"tag":53,"props":2057,"children":2059},{"className":2058},[],[2060],{"type":48,"value":1111},{"type":48,"value":2062},". Annotations survive context resets and are visible in the UI.",{"type":39,"tag":40,"props":2064,"children":2065},{},[2066,2072,2074,2079,2080,2085,2087,2092,2094,2099,2101,2111],{"type":39,"tag":53,"props":2067,"children":2069},{"className":2068},[],[2070],{"type":48,"value":2071},"?compareTo",{"type":48,"value":2073}," is a ",{"type":39,"tag":44,"props":2075,"children":2076},{},[2077],{"type":48,"value":2078},"live progress signal",{"type":48,"value":189},{"type":39,"tag":53,"props":2081,"children":2083},{"className":2082},[],[2084],{"type":48,"value":366},{"type":48,"value":2086}," writes state immediately, so ",{"type":39,"tag":53,"props":2088,"children":2090},{"className":2089},[],[2091],{"type":48,"value":396},{"type":48,"value":2093}," flips to ",{"type":39,"tag":53,"props":2095,"children":2097},{"className":2096},[],[2098],{"type":48,"value":758},{"type":48,"value":2100}," after each import. ",{"type":39,"tag":44,"props":2102,"children":2103},{},[2104,2106],{"type":48,"value":2105},"Do not run ",{"type":39,"tag":53,"props":2107,"children":2109},{"className":2108},[],[2110],{"type":48,"value":1859},{"type":48,"value":2112}," (see Phase 6).",{"type":39,"tag":40,"props":2114,"children":2115},{},[2116,2126],{"type":39,"tag":44,"props":2117,"children":2118},{},[2119,2121],{"type":48,"value":2120},"Reserve ",{"type":39,"tag":53,"props":2122,"children":2124},{"className":2123},[],[2125],{"type":48,"value":1111},{"type":48,"value":2127}," for cases where the computed status will be wrong:",{"type":39,"tag":277,"props":2129,"children":2130},{},[2131,2148],{"type":39,"tag":170,"props":2132,"children":2133},{},[2134,2139,2141,2146],{"type":39,"tag":53,"props":2135,"children":2137},{"className":2136},[],[2138],{"type":48,"value":1305},{"type":48,"value":2140}," (with ",{"type":39,"tag":53,"props":2142,"children":2144},{"className":2143},[],[2145],{"type":48,"value":1159},{"type":48,"value":2147},") — resource covered by another (inline IAM policy → parent Role, IGW attachment → IGW, etc.).",{"type":39,"tag":170,"props":2149,"children":2150},{},[2151,2156,2158,2163],{"type":39,"tag":53,"props":2152,"children":2154},{"className":2153},[],[2155],{"type":48,"value":1305},{"type":48,"value":2157}," (with a note, no ",{"type":39,"tag":53,"props":2159,"children":2161},{"className":2160},[],[2162],{"type":48,"value":1159},{"type":48,"value":2164},") — resource is deleted, dangling, or has no Pulumi equivalent. Flag it resolved so it drops out of the outstanding work.",{"type":39,"tag":233,"props":2166,"children":2168},{"id":2167},"phase-5-notfound-and-nomatch-triage",[2169],{"type":48,"value":2170},"Phase 5 — NotFound and NoMatch triage",{"type":39,"tag":40,"props":2172,"children":2173},{},[2174,2179,2181,2186],{"type":39,"tag":44,"props":2175,"children":2176},{},[2177],{"type":48,"value":2178},"Default strategy: try first, annotate second.",{"type":48,"value":2180}," For both NotFound and corrected-mapping cases, attempting ",{"type":39,"tag":53,"props":2182,"children":2184},{"className":2183},[],[2185],{"type":48,"value":366},{"type":48,"value":2187}," is the fastest way to learn what's actually wrong. The error messages are precise and actionable.",{"type":39,"tag":40,"props":2189,"children":2190},{},[2191,2195,2196,2201],{"type":39,"tag":44,"props":2192,"children":2193},{},[2194],{"type":48,"value":822},{"type":48,"value":51},{"type":39,"tag":53,"props":2197,"children":2199},{"className":2198},[],[2200],{"type":48,"value":331},{"type":48,"value":2202}," set, state unconfirmed):",{"type":39,"tag":40,"props":2204,"children":2205},{},[2206],{"type":48,"value":2207},"Common outcomes:",{"type":39,"tag":166,"props":2209,"children":2210},{},[2211,2250,2297,2355],{"type":39,"tag":170,"props":2212,"children":2213},{},[2214,2219,2221,2226,2228,2234,2236,2241,2243,2248],{"type":39,"tag":44,"props":2215,"children":2216},{},[2217],{"type":48,"value":2218},"Resource is deleted.",{"type":48,"value":2220}," ",{"type":39,"tag":53,"props":2222,"children":2224},{"className":2223},[],[2225],{"type":48,"value":366},{"type":48,"value":2227}," returns ",{"type":39,"tag":53,"props":2229,"children":2231},{"className":2230},[],[2232],{"type":48,"value":2233},"Preview failed: resource '\u003Cid>' does not exist",{"type":48,"value":2235},". Annotate ",{"type":39,"tag":53,"props":2237,"children":2239},{"className":2238},[],[2240],{"type":48,"value":1305},{"type":48,"value":2242}," with the literal error in the note. ",{"type":39,"tag":44,"props":2244,"children":2245},{},[2246],{"type":48,"value":2247},"Don't retry.",{"type":48,"value":2249}," In practice, a substantial share of NotFound resources turn out to be deleted rather than a mapping error.",{"type":39,"tag":170,"props":2251,"children":2252},{},[2253,2265,2267,2288,2290,2295],{"type":39,"tag":44,"props":2254,"children":2255},{},[2256,2258,2263],{"type":48,"value":2257},"Wrong ",{"type":39,"tag":53,"props":2259,"children":2261},{"className":2260},[],[2262],{"type":48,"value":331},{"type":48,"value":2264}," mapping.",{"type":48,"value":2266}," Import fails with a type-validation error or schema mismatch. Several CF types have multiple valid Pulumi mappings (VPC gateway attachment \u002F VPN vs IGW; S3 vs s3control; RDS instance vs cluster instance; SES v2 vs v1; etc.) — our scanner picks a primary that doesn't always match your resource. ",{"type":39,"tag":44,"props":2268,"children":2269},{},[2270,2272,2277,2279],{"type":48,"value":2271},"Look up the ",{"type":39,"tag":53,"props":2273,"children":2275},{"className":2274},[],[2276],{"type":48,"value":304},{"type":48,"value":2278}," in ",{"type":39,"tag":116,"props":2280,"children":2281},{"href":118},[2282],{"type":39,"tag":53,"props":2283,"children":2285},{"className":2284},[],[2286],{"type":48,"value":2287},"cloudformation.md §7",{"type":48,"value":2289},", override ",{"type":39,"tag":53,"props":2291,"children":2293},{"className":2292},[],[2294],{"type":48,"value":331},{"type":48,"value":2296}," in the import file, retry. Then handle the fingerprint side-effect (next bullet).",{"type":39,"tag":170,"props":2298,"children":2299},{},[2300,2305,2307,2312,2314,2319,2320,2325,2327,2332,2334,2353],{"type":39,"tag":44,"props":2301,"children":2302},{},[2303],{"type":48,"value":2304},"Wrong-mapping side-effect: PulumiOnly appears.",{"type":48,"value":2306}," When the agent imports with a corrected ",{"type":39,"tag":53,"props":2308,"children":2310},{"className":2309},[],[2311],{"type":48,"value":331},{"type":48,"value":2313},", fingerprint matching against the discovered resource fails. The discovered resource stays ",{"type":39,"tag":53,"props":2315,"children":2317},{"className":2316},[],[2318],{"type":48,"value":822},{"type":48,"value":1833},{"type":39,"tag":53,"props":2321,"children":2323},{"className":2322},[],[2324],{"type":48,"value":891},{"type":48,"value":2326},") and a new ",{"type":39,"tag":53,"props":2328,"children":2330},{"className":2329},[],[2331],{"type":48,"value":955},{"type":48,"value":2333}," entry appears. ",{"type":39,"tag":44,"props":2335,"children":2336},{},[2337,2339,2344,2346,2351],{"type":48,"value":2338},"Annotate the original origin row as ",{"type":39,"tag":53,"props":2340,"children":2342},{"className":2341},[],[2343],{"type":48,"value":1305},{"type":48,"value":2345}," with ",{"type":39,"tag":53,"props":2347,"children":2349},{"className":2348},[],[2350],{"type":48,"value":1159},{"type":48,"value":2352}," pointing to the PulumiOnly URN.",{"type":48,"value":2354}," This bridges them in the UI and keeps the bookkeeping clean.",{"type":39,"tag":170,"props":2356,"children":2357},{},[2358,2363,2365,2370],{"type":39,"tag":44,"props":2359,"children":2360},{},[2361],{"type":48,"value":2362},"Resource is alive and mapping is correct.",{"type":48,"value":2364}," Import succeeds. Status flips to ",{"type":39,"tag":53,"props":2366,"children":2368},{"className":2367},[],[2369],{"type":48,"value":758},{"type":48,"value":2371}," automatically.",{"type":39,"tag":40,"props":2373,"children":2374},{},[2375,2379,2380,2385,2386,2391],{"type":39,"tag":44,"props":2376,"children":2377},{},[2378],{"type":48,"value":891},{"type":48,"value":51},{"type":39,"tag":53,"props":2381,"children":2383},{"className":2382},[],[2384],{"type":48,"value":331},{"type":48,"value":899},{"type":39,"tag":53,"props":2387,"children":2389},{"className":2388},[],[2390],{"type":48,"value":347},{"type":48,"value":2392},"):",{"type":39,"tag":40,"props":2394,"children":2395},{},[2396],{"type":48,"value":2397},"Common patterns:",{"type":39,"tag":166,"props":2399,"children":2400},{},[2401,2439,2456,2497],{"type":39,"tag":170,"props":2402,"children":2403},{},[2404,2409,2410,2415,2417,2423,2425,2430,2432,2438],{"type":39,"tag":44,"props":2405,"children":2406},{},[2407],{"type":48,"value":2408},"Inline IAM policies.",{"type":48,"value":2220},{"type":39,"tag":53,"props":2411,"children":2413},{"className":2412},[],[2414],{"type":48,"value":933},{"type":48,"value":2416}," whose name matches a migrated Role's prefix is an inline policy already captured as ",{"type":39,"tag":53,"props":2418,"children":2420},{"className":2419},[],[2421],{"type":48,"value":2422},"inlinePolicies",{"type":48,"value":2424}," on the Role's import. Annotate ",{"type":39,"tag":53,"props":2426,"children":2428},{"className":2427},[],[2429],{"type":48,"value":1305},{"type":48,"value":2431}," with note: ",{"type":39,"tag":53,"props":2433,"children":2435},{"className":2434},[],[2436],{"type":48,"value":2437},"\"inline policy of \u003CRoleName>\"",{"type":48,"value":368},{"type":39,"tag":170,"props":2440,"children":2441},{},[2442,2447,2449,2454],{"type":39,"tag":44,"props":2443,"children":2444},{},[2445],{"type":48,"value":2446},"AWS::SecretsManager::SecretTargetAttachment",{"type":48,"value":2448}," has no direct Pulumi mapping. The link between secret and target (RDS cluster, etc.) is implicit via the cluster's credentials config. Annotate ",{"type":39,"tag":53,"props":2450,"children":2452},{"className":2451},[],[2453],{"type":48,"value":1305},{"type":48,"value":2455}," with a note explaining the implicit link.",{"type":39,"tag":170,"props":2457,"children":2458},{},[2459,2464,2465,2471,2473,2481,2483,2495],{"type":39,"tag":44,"props":2460,"children":2461},{},[2462],{"type":48,"value":2463},"CDK Custom Resources",{"type":48,"value":51},{"type":39,"tag":53,"props":2466,"children":2468},{"className":2467},[],[2469],{"type":48,"value":2470},"Custom::*",{"type":48,"value":2472},"). Typically a Lambda handler doing the actual work. Check ",{"type":39,"tag":116,"props":2474,"children":2475},{"href":118},[2476],{"type":39,"tag":53,"props":2477,"children":2479},{"className":2478},[],[2480],{"type":48,"value":547},{"type":48,"value":2482}," for known handler → Pulumi replacement mappings. ",{"type":39,"tag":44,"props":2484,"children":2485},{},[2486,2488,2493],{"type":48,"value":2487},"Don't annotate ",{"type":39,"tag":53,"props":2489,"children":2491},{"className":2490},[],[2492],{"type":48,"value":758},{"type":48,"value":2494}," without confirming with the user",{"type":48,"value":2496}," — surface what the handler does and let them decide.",{"type":39,"tag":170,"props":2498,"children":2499},{},[2500,2505,2507,2512],{"type":39,"tag":44,"props":2501,"children":2502},{},[2503],{"type":48,"value":2504},"Other NoMatch types.",{"type":48,"value":2506}," Look up the ",{"type":39,"tag":53,"props":2508,"children":2510},{"className":2509},[],[2511],{"type":48,"value":304},{"type":48,"value":2513}," in the cloud provider docs (CF resource type reference or ARM resource type reference) to understand what the resource is, then search the Pulumi registry for a matching provider type. If the mapping is ambiguous, surface to the user and ask.",{"type":39,"tag":40,"props":2515,"children":2516},{},[2517,2522,2524,2529],{"type":39,"tag":44,"props":2518,"children":2519},{},[2520],{"type":48,"value":2521},"Pre-existing PulumiOnly entries.",{"type":48,"value":2523}," Beyond the corrected-mapping artifacts above, ",{"type":39,"tag":53,"props":2525,"children":2527},{"className":2526},[],[2528],{"type":48,"value":955},{"type":48,"value":2530}," also covers resources already in the target stack that aren't part of this migration. Leave those as-is — no annotation needed.",{"type":39,"tag":62,"props":2532,"children":2533},{},[2534],{"type":39,"tag":40,"props":2535,"children":2536},{},[2537,2539,2544,2546,2551,2552,2557,2559,2565,2567,2576,2577,2586],{"type":48,"value":2538},"For cloud-specific lookup commands (verifying resources exist, finding import IDs, querying the cloud), provider-choice rules (",{"type":39,"tag":53,"props":2540,"children":2542},{"className":2541},[],[2543],{"type":48,"value":104},{"type":48,"value":2545}," classic vs ",{"type":39,"tag":53,"props":2547,"children":2549},{"className":2548},[],[2550],{"type":48,"value":96},{"type":48,"value":314},{"type":39,"tag":53,"props":2553,"children":2555},{"className":2554},[],[2556],{"type":48,"value":112},{"type":48,"value":2558}," vs ",{"type":39,"tag":53,"props":2560,"children":2562},{"className":2561},[],[2563],{"type":48,"value":2564},"azure",{"type":48,"value":2566},"), the Preview Resolution Workflow, and known import quirks, see ",{"type":39,"tag":116,"props":2568,"children":2569},{"href":118},[2570],{"type":39,"tag":53,"props":2571,"children":2573},{"className":2572},[],[2574],{"type":48,"value":2575},"cloudformation.md §3–§6",{"type":48,"value":80},{"type":39,"tag":116,"props":2578,"children":2579},{"href":129},[2580],{"type":39,"tag":53,"props":2581,"children":2583},{"className":2582},[],[2584],{"type":48,"value":2585},"arm.md §3–§6",{"type":48,"value":368},{"type":39,"tag":233,"props":2588,"children":2590},{"id":2589},"phase-6-reconciliation-pr",[2591],{"type":48,"value":2592},"Phase 6 — Reconciliation & PR",{"type":39,"tag":166,"props":2594,"children":2595},{},[2596,2735,2805],{"type":39,"tag":170,"props":2597,"children":2598},{},[2599,2601,2606,2607,2612,2614,2695,2698,2700,2712,2714,2723,2724,2733],{"type":48,"value":2600},"Run ",{"type":39,"tag":53,"props":2602,"children":2604},{"className":2603},[],[2605],{"type":48,"value":195},{"type":48,"value":189},{"type":39,"tag":44,"props":2608,"children":2609},{},[2610],{"type":48,"value":2611},"confirm there are NO changes",{"type":48,"value":2613},". Any diff means the generated code doesn't match the imported state. Diffs come in three shapes:",{"type":39,"tag":277,"props":2615,"children":2616},{},[2617,2648,2672],{"type":39,"tag":170,"props":2618,"children":2619},{},[2620,2632,2634,2639,2641,2647],{"type":39,"tag":44,"props":2621,"children":2622},{},[2623,2625,2631],{"type":48,"value":2624},"Removed (",{"type":39,"tag":53,"props":2626,"children":2628},{"className":2627},[],[2629],{"type":48,"value":2630},"-",{"type":48,"value":322},{"type":48,"value":2633}," — a field the cloud has but your code doesn't set. ",{"type":39,"tag":44,"props":2635,"children":2636},{},[2637],{"type":48,"value":2638},"Add it to the code",{"type":48,"value":2640}," with the real cloud value. Don't ",{"type":39,"tag":53,"props":2642,"children":2644},{"className":2643},[],[2645],{"type":48,"value":2646},"ignoreChanges",{"type":48,"value":368},{"type":39,"tag":170,"props":2649,"children":2650},{},[2651,2663,2665,2670],{"type":39,"tag":44,"props":2652,"children":2653},{},[2654,2656,2662],{"type":48,"value":2655},"Added (",{"type":39,"tag":53,"props":2657,"children":2659},{"className":2658},[],[2660],{"type":48,"value":2661},"+",{"type":48,"value":322},{"type":48,"value":2664}," — a field your code sets that the provider didn't return. If computed\u002Fread-only → ",{"type":39,"tag":53,"props":2666,"children":2668},{"className":2667},[],[2669],{"type":48,"value":2646},{"type":48,"value":2671},". If a provider default re-statement → remove from code.",{"type":39,"tag":170,"props":2673,"children":2674},{},[2675,2687,2689,2694],{"type":39,"tag":44,"props":2676,"children":2677},{},[2678,2680,2686],{"type":48,"value":2679},"Changed (",{"type":39,"tag":53,"props":2681,"children":2683},{"className":2682},[],[2684],{"type":48,"value":2685},"~",{"type":48,"value":322},{"type":48,"value":2688}," — value mismatch. Query the cloud, determine the correct value, update code. Never silence with ",{"type":39,"tag":53,"props":2690,"children":2692},{"className":2691},[],[2693],{"type":48,"value":2646},{"type":48,"value":368},{"type":39,"tag":1377,"props":2696,"children":2697},{},[],{"type":48,"value":2699},"Expect 2–5 preview rounds for complex resources. ",{"type":39,"tag":44,"props":2701,"children":2702},{},[2703,2705,2710],{"type":48,"value":2704},"Never run ",{"type":39,"tag":53,"props":2706,"children":2708},{"className":2707},[],[2709],{"type":48,"value":1859},{"type":48,"value":2711}," to resolve diffs — that modifies the cloud, not the code.",{"type":48,"value":2713}," See ",{"type":39,"tag":116,"props":2715,"children":2716},{"href":118},[2717],{"type":39,"tag":53,"props":2718,"children":2720},{"className":2719},[],[2721],{"type":48,"value":2722},"cloudformation.md §6",{"type":48,"value":80},{"type":39,"tag":116,"props":2725,"children":2726},{"href":129},[2727],{"type":39,"tag":53,"props":2728,"children":2730},{"className":2729},[],[2731],{"type":48,"value":2732},"arm.md §6",{"type":48,"value":2734}," for cloud-specific diff patterns.",{"type":39,"tag":170,"props":2736,"children":2737},{},[2738,2740,2746,2748,2753,2755,2760,2762],{"type":48,"value":2739},"Do one final ",{"type":39,"tag":53,"props":2741,"children":2743},{"className":2742},[],[2744],{"type":48,"value":2745},"GET resources?compareTo=...",{"type":48,"value":2747}," and verify the expected distribution (this reflects the current backend state — ",{"type":39,"tag":53,"props":2749,"children":2751},{"className":2750},[],[2752],{"type":48,"value":396},{"type":48,"value":2754}," is already up-to-date since every ",{"type":39,"tag":53,"props":2756,"children":2758},{"className":2757},[],[2759],{"type":48,"value":366},{"type":48,"value":2761}," writes state):",{"type":39,"tag":277,"props":2763,"children":2764},{},[2765,2775,2785,2795],{"type":39,"tag":170,"props":2766,"children":2767},{},[2768,2773],{"type":39,"tag":53,"props":2769,"children":2771},{"className":2770},[],[2772],{"type":48,"value":758},{"type":48,"value":2774}," — all imported resources",{"type":39,"tag":170,"props":2776,"children":2777},{},[2778,2783],{"type":39,"tag":53,"props":2779,"children":2781},{"className":2780},[],[2782],{"type":48,"value":955},{"type":48,"value":2784}," — Pulumi-only resources, including any corrected-mapping imports linked via annotation",{"type":39,"tag":170,"props":2786,"children":2787},{},[2788,2793],{"type":39,"tag":53,"props":2789,"children":2791},{"className":2790},[],[2792],{"type":48,"value":891},{"type":48,"value":2794}," remaining — every one should have an annotation",{"type":39,"tag":170,"props":2796,"children":2797},{},[2798,2803],{"type":39,"tag":53,"props":2799,"children":2801},{"className":2800},[],[2802],{"type":48,"value":848},{"type":48,"value":2804}," (containers) — silently skipped",{"type":39,"tag":170,"props":2806,"children":2807},{},[2808,2810,2815],{"type":48,"value":2809},"Proceed to Phase 7 (refactor offer) ",{"type":39,"tag":44,"props":2811,"children":2812},{},[2813],{"type":48,"value":2814},"before",{"type":48,"value":2816}," opening the PR.",{"type":39,"tag":40,"props":2818,"children":2819},{},[2820,2822,2832,2834,2839,2841,2846],{"type":48,"value":2821},"The migration is functionally complete when preview is clean and the API triage shows no unresolved resources. ",{"type":39,"tag":44,"props":2823,"children":2824},{},[2825,2826,2831],{"type":48,"value":2105},{"type":39,"tag":53,"props":2827,"children":2829},{"className":2828},[],[2830],{"type":48,"value":1859},{"type":48,"value":368},{"type":48,"value":2833}," The imported state is already synced to Pulumi Cloud via ",{"type":39,"tag":53,"props":2835,"children":2837},{"className":2836},[],[2838],{"type":48,"value":366},{"type":48,"value":2840},"; there's nothing for ",{"type":39,"tag":53,"props":2842,"children":2844},{"className":2843},[],[2845],{"type":48,"value":1859},{"type":48,"value":2847}," to do that serves the migration.",{"type":39,"tag":139,"props":2849,"children":2850},{},[],{"type":39,"tag":233,"props":2852,"children":2854},{"id":2853},"phase-7-refactor-and-maintainability-review-before-the-pr",[2855],{"type":48,"value":2856},"Phase 7 — Refactor and maintainability review (before the PR)",{"type":39,"tag":40,"props":2858,"children":2859},{},[2860,2862,2867],{"type":48,"value":2861},"Zero-diff is achieved, but the imported code is \"flat\" — hardcoded values, no cross-resource references, all resources at the top level. ",{"type":39,"tag":44,"props":2863,"children":2864},{},[2865],{"type":48,"value":2866},"Before opening the PR",{"type":48,"value":2868},", offer the user a readability refactor.",{"type":39,"tag":40,"props":2870,"children":2871},{},[2872],{"type":39,"tag":44,"props":2873,"children":2874},{},[2875],{"type":48,"value":2876},"7a — Offer and orient",{"type":39,"tag":40,"props":2878,"children":2879},{},[2880,2882,2887],{"type":48,"value":2881},"If Phase 0 didn't capture explicit refactor preferences, or the user hasn't explicitly declined, ",{"type":39,"tag":44,"props":2883,"children":2884},{},[2885],{"type":48,"value":2886},"ask now",{"type":48,"value":439},{"type":39,"tag":62,"props":2889,"children":2890},{},[2891],{"type":39,"tag":40,"props":2892,"children":2893},{},[2894],{"type":48,"value":2895},"\"Preview is clean and all resources are accounted for. Before I open the PR, I'd like to refactor the code for maintainability — replacing any hardcoding with cross-resource references, extracting config parameters, and grouping related resources. (If you gave me a source repo, I'll use it as the structural blueprint, matching the intended file layout and component names.) Want me to go ahead?\"",{"type":39,"tag":40,"props":2897,"children":2898},{},[2899],{"type":48,"value":2900},"If they decline, skip to Phase 8.",{"type":39,"tag":40,"props":2902,"children":2903},{},[2904],{"type":39,"tag":44,"props":2905,"children":2906},{},[2907],{"type":48,"value":2908},"7b — Implement the refactor",{"type":39,"tag":40,"props":2910,"children":2911},{},[2912,2914,2923],{"type":48,"value":2913},"Read ",{"type":39,"tag":116,"props":2915,"children":2917},{"href":2916},"refactor.md",[2918],{"type":39,"tag":53,"props":2919,"children":2921},{"className":2920},[],[2922],{"type":48,"value":2916},{"type":48,"value":2924}," for strategies, invariants, and template-reading references. Key priorities in order:",{"type":39,"tag":166,"props":2926,"children":2927},{},[2928,2938,2948,2958,2976],{"type":39,"tag":170,"props":2929,"children":2930},{},[2931,2936],{"type":39,"tag":44,"props":2932,"children":2933},{},[2934],{"type":48,"value":2935},"Take structural cues from the source repo first",{"type":48,"value":2937}," — if the user provided a source repo, read it now (clone or use the local path from Phase 0). Use its file layout, component\u002Fmodule boundaries, and naming conventions as a guide. Where a group of resources maps naturally to a class, module, or subdirectory in the source and that grouping still feels natural for the imported Pulumi program, mirror that structure; otherwise avoid forcing artificial groupings just to match the source mechanically.",{"type":39,"tag":170,"props":2939,"children":2940},{},[2941,2946],{"type":39,"tag":44,"props":2942,"children":2943},{},[2944],{"type":48,"value":2945},"Replace literal ARN\u002FID references",{"type":48,"value":2947}," with cross-resource output references.",{"type":39,"tag":170,"props":2949,"children":2950},{},[2951,2956],{"type":39,"tag":44,"props":2952,"children":2953},{},[2954],{"type":48,"value":2955},"Extract config parameters",{"type":48,"value":2957}," (region, account ID, environment tag).",{"type":39,"tag":170,"props":2959,"children":2960},{},[2961,2974],{"type":39,"tag":44,"props":2962,"children":2963},{},[2964,2966,2972],{"type":48,"value":2965},"Consolidate into ",{"type":39,"tag":53,"props":2967,"children":2969},{"className":2968},[],[2970],{"type":48,"value":2971},"ComponentResource",{"type":48,"value":2973}," classes",{"type":48,"value":2975}," where the source repo or CDK paths suggest a natural grouping.",{"type":39,"tag":170,"props":2977,"children":2978},{},[2979,2984],{"type":39,"tag":44,"props":2980,"children":2981},{},[2982],{"type":48,"value":2983},"Split into files",{"type":48,"value":2985}," only last — and only when a natural isle warrants it.",{"type":39,"tag":40,"props":2987,"children":2988},{},[2989,2990,2995,2997,3007],{"type":48,"value":2600},{"type":39,"tag":53,"props":2991,"children":2993},{"className":2992},[],[2994],{"type":48,"value":195},{"type":48,"value":2996}," after every non-trivial change. Zero-diff must hold throughout. If preview shows a diff, revert that single change before trying anything else — see ",{"type":39,"tag":116,"props":2998,"children":2999},{"href":2916},[3000,3005],{"type":39,"tag":53,"props":3001,"children":3003},{"className":3002},[],[3004],{"type":48,"value":2916},{"type":48,"value":3006}," § The invariant",{"type":48,"value":3008}," for recovery steps.",{"type":39,"tag":40,"props":3010,"children":3011},{},[3012],{"type":39,"tag":44,"props":3013,"children":3014},{},[3015],{"type":48,"value":3016},"7c — User walkthrough and maintainability sign-off",{"type":39,"tag":40,"props":3018,"children":3019},{},[3020,3022,3027],{"type":48,"value":3021},"After the refactor, ",{"type":39,"tag":44,"props":3023,"children":3024},{},[3025],{"type":48,"value":3026},"present the result to the user before opening the PR",{"type":48,"value":439},{"type":39,"tag":166,"props":3029,"children":3030},{},[3031,3036,3049,3070],{"type":39,"tag":170,"props":3032,"children":3033},{},[3034],{"type":48,"value":3035},"Show a summary of what changed: files created\u002Frenamed, components introduced, literals replaced, config keys added.",{"type":39,"tag":170,"props":3037,"children":3038},{},[3039,3041,3047],{"type":48,"value":3040},"Walk through the top-level ",{"type":39,"tag":53,"props":3042,"children":3044},{"className":3043},[],[3045],{"type":48,"value":3046},"index.ts",{"type":48,"value":3048}," (or equivalent) line by line if it's under ~80 lines; otherwise describe the module breakdown.",{"type":39,"tag":170,"props":3050,"children":3051},{},[3052,3054,3060,3062,3068],{"type":48,"value":3053},"Highlight any judgment calls (e.g. \"I grouped the IAM resources into ",{"type":39,"tag":53,"props":3055,"children":3057},{"className":3056},[],[3058],{"type":48,"value":3059},"iam.ts",{"type":48,"value":3061}," to match the ",{"type":39,"tag":53,"props":3063,"children":3065},{"className":3064},[],[3066],{"type":48,"value":3067},"lib\u002Fiam\u002F",{"type":48,"value":3069}," directory in your source repo — let me know if you'd prefer a different name\").",{"type":39,"tag":170,"props":3071,"children":3072},{},[3073,3075,3080],{"type":48,"value":3074},"Ask explicitly: ",{"type":39,"tag":44,"props":3076,"children":3077},{},[3078],{"type":48,"value":3079},"\"Does this structure match how you'd expect to maintain this code?\"",{"type":48,"value":3081}," Wait for the user's answer. If they request changes, make them (always preview after) and repeat the walkthrough until they're satisfied.",{"type":39,"tag":40,"props":3083,"children":3084},{},[3085],{"type":48,"value":3086},"Only proceed to Phase 8 once the user confirms the structure is acceptable.",{"type":39,"tag":139,"props":3088,"children":3089},{},[],{"type":39,"tag":233,"props":3091,"children":3093},{"id":3092},"phase-8-pr-and-migration-report",[3094],{"type":48,"value":3095},"Phase 8 — PR and migration report",{"type":39,"tag":40,"props":3097,"children":3098},{},[3099],{"type":48,"value":3100},"Produce the migration report (see below) and open the PR. The PR includes whatever state the code is in — raw imported code (if the user skipped Phase 7) or the refactored version (if they opted in).",{"type":39,"tag":139,"props":3102,"children":3103},{},[],{"type":39,"tag":143,"props":3105,"children":3107},{"id":3106},"migration-report-format",[3108],{"type":48,"value":3109},"MIGRATION REPORT FORMAT",{"type":39,"tag":40,"props":3111,"children":3112},{},[3113],{"type":48,"value":3114},"Include in the PR description:",{"type":39,"tag":166,"props":3116,"children":3117},{},[3118,3128,3138,3148,3158,3168],{"type":39,"tag":170,"props":3119,"children":3120},{},[3121,3126],{"type":39,"tag":44,"props":3122,"children":3123},{},[3124],{"type":48,"value":3125},"Overview",{"type":48,"value":3127}," — source discovered stack → target Pulumi stack, region, language.",{"type":39,"tag":170,"props":3129,"children":3130},{},[3131,3136],{"type":39,"tag":44,"props":3132,"children":3133},{},[3134],{"type":48,"value":3135},"Triage summary",{"type":48,"value":3137}," — counts by status at start and end.",{"type":39,"tag":170,"props":3139,"children":3140},{},[3141,3146],{"type":39,"tag":44,"props":3142,"children":3143},{},[3144],{"type":48,"value":3145},"Resource mapping table",{"type":48,"value":3147}," — name, origin type, provider type, status, notes.",{"type":39,"tag":170,"props":3149,"children":3150},{},[3151,3156],{"type":39,"tag":44,"props":3152,"children":3153},{},[3154],{"type":48,"value":3155},"Gaps",{"type":48,"value":3157}," — unmapped resources and why, with annotations.",{"type":39,"tag":170,"props":3159,"children":3160},{},[3161,3166],{"type":39,"tag":44,"props":3162,"children":3163},{},[3164],{"type":48,"value":3165},"Progress URL",{"type":48,"value":3167}," — link to the discovered-stacks comparison endpoint for ongoing tracking.",{"type":39,"tag":170,"props":3169,"children":3170},{},[3171,3176],{"type":39,"tag":44,"props":3172,"children":3173},{},[3174],{"type":48,"value":3175},"Next steps",{"type":48,"value":3177}," — pending user decisions, optional refactoring.",{"type":39,"tag":3179,"props":3180,"children":3181},"style",{},[3182],{"type":48,"value":3183},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":3185,"total":3342},[3186,3200,3215,3228,3240,3255,3270,3282,3297,3310,3325,3332],{"slug":78,"name":78,"fn":3187,"description":3188,"org":3189,"tags":3190,"stars":23,"repoUrl":24,"updatedAt":3199},"migrate CloudFormation to Pulumi","Convert, migrate, or import AWS CloudFormation stacks or templates into Pulumi programs. Load this skill whenever a user wants to move from CloudFormation to Pulumi, convert a CFN template, import existing CloudFormation-managed resources into Pulumi, or asks about CloudFormation-to-Pulumi migration in any form. Also load when the user mentions cdk-importer in a migration context.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3191,3193,3196,3197,3198],{"name":3192,"slug":104,"type":13},"AWS",{"name":3194,"slug":3195,"type":13},"Deployment","deployment",{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},"2026-04-06T18:50:36.677615",{"slug":3201,"name":3201,"fn":3202,"description":3203,"org":3204,"tags":3205,"stars":23,"repoUrl":24,"updatedAt":3214},"package-usage","audit Pulumi package usage across stacks","Track which stacks across a Pulumi organization use a specific package and at what versions. Use for cross-stack audits, identifying outdated or unmaintained package versions across many stacks, finding affected stacks before publishing breaking changes to a component package, or planning coordinated upgrade rollouts. Do NOT use for upgrading a cloud provider package (pulumi-aws, pulumi-azure-native, pulumi-gcp, pulumi-kubernetes, etc.) in a single project — use skill `provider-upgrade` instead. Do NOT use for general infrastructure creation, resource provisioning, or how-to questions about a package.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3206,3209,3210,3213],{"name":3207,"slug":3208,"type":13},"Audit","audit",{"name":21,"slug":22,"type":13},{"name":3211,"slug":3212,"type":13},"Operations","operations",{"name":9,"slug":8,"type":13},"2026-07-24T05:37:48.019964",{"slug":3216,"name":3216,"fn":3217,"description":3218,"org":3219,"tags":3220,"stars":23,"repoUrl":24,"updatedAt":3227},"provider-upgrade","upgrade and reconcile Pulumi providers","Upgrade any Pulumi provider to a newer version and reconcile the resulting diff. Use when users want to upgrade or update a provider (including editing package.json, requirements.txt, pyproject.toml, go.mod, or Pulumi.yaml to bump a provider SDK), check for breaking changes before or during an upgrade, fix resources that broke after a provider upgrade, or resolve unexpected replacements, creates, or deletes in a post-upgrade preview. Applies to all providers (aws, azure-native, gcp, kubernetes, aws-native, cloudflare, datadog, etc.) — not just Tier 1. Do NOT use for querying which stacks use what package versions; use skill `package-usage` for cross-stack audits. Do NOT use for general infrastructure tasks.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3221,3224,3225,3226],{"name":3222,"slug":3223,"type":13},"DevOps","devops",{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},"2026-06-04T07:58:58.874758",{"slug":86,"name":86,"fn":3229,"description":3230,"org":3231,"tags":3232,"stars":23,"repoUrl":24,"updatedAt":3239},"migrate Azure ARM to Pulumi","Convert or migrate Azure ARM (Azure Resource Manager) templates, Bicep templates, or code to Pulumi, including importing existing Azure resources. This skill MUST be loaded whenever a user requests migration, conversion, or import of ARM templates, Bicep templates, ARM code, Bicep code, or Azure resources to Pulumi.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3233,3235,3236,3237,3238],{"name":3234,"slug":2564,"type":13},"Azure",{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},"2026-04-06T18:50:35.384851",{"slug":3241,"name":3241,"fn":3242,"description":3243,"org":3244,"tags":3245,"stars":23,"repoUrl":24,"updatedAt":3254},"pulumi-automation-api","run Pulumi programs via Automation API","Load this skill when a user asks how to run Pulumi programmatically, embed Pulumi in an application, orchestrate multiple stacks in code, build a self-service infrastructure portal, replace pulumi CLI shell scripts with code, or use the Pulumi Automation API (LocalWorkspace, createOrSelectStack, inline programs). Also load for questions about multi-stack sequencing, parallel deployments, or passing outputs between stacks via code.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3246,3249,3252,3253],{"name":3247,"slug":3248,"type":13},"API Development","api-development",{"name":3250,"slug":3251,"type":13},"Automation","automation",{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},"2026-06-04T07:59:00.113998",{"slug":3256,"name":3256,"fn":3257,"description":3258,"org":3259,"tags":3260,"stars":23,"repoUrl":24,"updatedAt":3269},"pulumi-best-practices","apply Pulumi best practices for infrastructure","Load when the user is writing, reviewing, or debugging Pulumi TypeScript\u002FPython programs; asks about Output\u003CT> or apply() usage; wants to create ComponentResource classes; needs to refactor resources without destroying them (aliases); is setting up secrets or config; or is configuring a pulumi preview\u002Fup CI workflow. Also load for questions about resource dependency order, parent\u002Fchild resource relationships, or pulumi.interpolate.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3261,3262,3263,3266],{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},{"name":3264,"slug":3265,"type":13},"Python","python",{"name":3267,"slug":3268,"type":13},"TypeScript","typescript","2026-06-03T07:52:43.916562",{"slug":3271,"name":3271,"fn":3272,"description":3273,"org":3274,"tags":3275,"stars":23,"repoUrl":24,"updatedAt":3281},"pulumi-cdk-to-pulumi","migrate AWS CDK to Pulumi","Load this skill when a user wants to migrate, convert, port, translate, or move an AWS CDK application (including CDK stacks, constructs, or CloudFormation-synthesized templates) to Pulumi. Phrases such as \"convert CDK to Pulumi\", \"migrate CDK app\", \"port CDK stacks\", \"replace CDK with Pulumi\", \"stop using CDK\". Do NOT load for general CDK questions, CDK-only help, or CDK vs Pulumi comparisons where no migration is requested.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3276,3277,3278,3279,3280],{"name":3192,"slug":104,"type":13},{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},"2026-04-06T18:50:39.23999",{"slug":3283,"name":3283,"fn":3284,"description":3285,"org":3286,"tags":3287,"stars":23,"repoUrl":24,"updatedAt":3296},"pulumi-component","author reusable Pulumi component resources","Guide for authoring Pulumi ComponentResource classes. Use when creating reusable infrastructure components, designing component interfaces, setting up multi-language support, or distributing component packages.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3288,3291,3294,3295],{"name":3289,"slug":3290,"type":13},"Architecture","architecture",{"name":3292,"slug":3293,"type":13},"Engineering","engineering",{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},"2026-06-04T07:58:57.625622",{"slug":3298,"name":3298,"fn":3299,"description":3300,"org":3301,"tags":3302,"stars":23,"repoUrl":24,"updatedAt":3309},"pulumi-debug-failed-operation","debug failed Pulumi operations","Debug a Pulumi update or preview that failed: read the failure Pulumi already\nrecorded, find what caused it, and fix it. Load this skill when the user asks\nto debug, diagnose, or fix a failed update or preview, or points at a failing\n`pulumi up` or `pulumi preview`. Don't load it for authoring new\ninfrastructure, migrations, or provider upgrades; those have their own skills.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3303,3306,3307,3308],{"name":3304,"slug":3305,"type":13},"Debugging","debugging",{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},"2026-07-08T05:47:02.688144",{"slug":3311,"name":3311,"fn":3312,"description":3313,"org":3314,"tags":3315,"stars":23,"repoUrl":24,"updatedAt":3324},"pulumi-esc","manage secrets and configuration with Pulumi ESC","Guidance for working with Pulumi ESC (Environments, Secrets, and Configuration). Use when users ask about managing secrets, configuration, environments, short-term credentials, configuring OIDC for AWS, Azure, GCP, integrating with secret stores (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, 1Password), or using ESC with Pulumi stacks.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3316,3319,3320,3321],{"name":3317,"slug":3318,"type":13},"Configuration","configuration",{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},{"name":3322,"slug":3323,"type":13},"Security","security","2026-07-24T05:37:47.044405",{"slug":4,"name":4,"fn":5,"description":6,"org":3326,"tags":3327,"stars":23,"repoUrl":24,"updatedAt":25},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3328,3329,3330,3331],{"name":18,"slug":19,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},{"slug":3333,"name":3333,"fn":3334,"description":3335,"org":3336,"tags":3337,"stars":23,"repoUrl":24,"updatedAt":3341},"pulumi-overview","manage cloud infrastructure with Pulumi","Use this skill for any task that creates, modifies, inspects, or destroys cloud infrastructure or SaaS configuration, from one-off CLI operations to full multi-resource projects, across providers in the Pulumi ecosystem. A typical project spans many providers (AWS or Azure or GCP, Kubernetes, Cloudflare, Auth0, Datadog, Vercel, and others), and Pulumi drives them through one CLI, one state model, and one credential layer. Trigger even when the user does not name Pulumi; phrasings like \"deploy this app,\" \"provision a database,\" \"stand up a VPC,\" \"configure Auth0,\" \"set up Datadog monitoring,\" or \"tear down staging\" qualify. Also trigger for tasks that migrate, port, or convert existing infrastructure code (Terraform, CloudFormation, CDK, Bicep, ARM) to Pulumi. Do not trigger for application runtime code that reads or writes data via cloud SDKs; that is application code, not infrastructure.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3338,3339,3340],{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},"2026-06-03T07:52:39.333565",13,{"items":3344,"total":3342},[3345,3353,3360,3367,3375,3382,3389],{"slug":78,"name":78,"fn":3187,"description":3188,"org":3346,"tags":3347,"stars":23,"repoUrl":24,"updatedAt":3199},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3348,3349,3350,3351,3352],{"name":3192,"slug":104,"type":13},{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},{"slug":3201,"name":3201,"fn":3202,"description":3203,"org":3354,"tags":3355,"stars":23,"repoUrl":24,"updatedAt":3214},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3356,3357,3358,3359],{"name":3207,"slug":3208,"type":13},{"name":21,"slug":22,"type":13},{"name":3211,"slug":3212,"type":13},{"name":9,"slug":8,"type":13},{"slug":3216,"name":3216,"fn":3217,"description":3218,"org":3361,"tags":3362,"stars":23,"repoUrl":24,"updatedAt":3227},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3363,3364,3365,3366],{"name":3222,"slug":3223,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},{"slug":86,"name":86,"fn":3229,"description":3230,"org":3368,"tags":3369,"stars":23,"repoUrl":24,"updatedAt":3239},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3370,3371,3372,3373,3374],{"name":3234,"slug":2564,"type":13},{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13},{"slug":3241,"name":3241,"fn":3242,"description":3243,"org":3376,"tags":3377,"stars":23,"repoUrl":24,"updatedAt":3254},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3378,3379,3380,3381],{"name":3247,"slug":3248,"type":13},{"name":3250,"slug":3251,"type":13},{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},{"slug":3256,"name":3256,"fn":3257,"description":3258,"org":3383,"tags":3384,"stars":23,"repoUrl":24,"updatedAt":3269},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3385,3386,3387,3388],{"name":21,"slug":22,"type":13},{"name":9,"slug":8,"type":13},{"name":3264,"slug":3265,"type":13},{"name":3267,"slug":3268,"type":13},{"slug":3271,"name":3271,"fn":3272,"description":3273,"org":3390,"tags":3391,"stars":23,"repoUrl":24,"updatedAt":3281},{"slug":8,"name":9,"logoUrl":10,"githubOrg":8},[3392,3393,3394,3395,3396],{"name":3192,"slug":104,"type":13},{"name":3194,"slug":3195,"type":13},{"name":21,"slug":22,"type":13},{"name":15,"slug":16,"type":13},{"name":9,"slug":8,"type":13}]