<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0"><channel><title>Pulumi Blog: Product</title><link>https://www.pulumi.com/blog/categories/product/</link><description>Pulumi blog posts: Product.</description><language>en-us</language><pubDate>Tue, 06 Oct 2026 08:00:00 -0700</pubDate><item><title>Pulumi Google Cloud Provider Version 10.0.0</title><link>https://www.pulumi.com/blog/gcp-v10-release/</link><pubDate>Tue, 06 Oct 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/gcp-v10-release/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/gcp-v10-release/index.png" /&gt;
&lt;p&gt;&lt;strong&gt;TL;DR: we are releasing a new major version of the Google Cloud provider. To migrate, ask Neo or your coding agent to run the Pulumi &lt;code&gt;provider-upgrade&lt;/code&gt; skill (&lt;a href="#use-an-agent-to-assist-with-your-upgrade"&gt;how to use it&lt;/a&gt;) or follow the &lt;a href="https://www.pulumi.com/registry/packages/gcp/how-to-guides/10-0-migration/"&gt;v10 migration guide&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We are happy to announce the next major version of the Pulumi Google Cloud provider. This release is based on the new &lt;a href="https://github.com/hashicorp/terraform-provider-google/releases/tag/v8.0.0"&gt;v8 major version of terraform-provider-google&lt;/a&gt; (see also the &lt;a href="https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/guides/version_8_upgrade"&gt;upstream v8 upgrade guide&lt;/a&gt;). It ships with a &lt;a href="https://www.pulumi.com/registry/packages/gcp/how-to-guides/10-0-migration/"&gt;migration guide&lt;/a&gt; that covers every breaking change in depth.&lt;/p&gt;
&lt;p&gt;Here are a few links to help you get started if you are new to Pulumi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/iac/get-started/gcp/"&gt;Getting Started&lt;/a&gt;: a guided walkthrough for creating your first project&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/gcp/installation-configuration/"&gt;Setup &amp;amp; Install&lt;/a&gt;: how to install the Google Cloud provider&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/registry/packages/gcp/how-to-guides/"&gt;How-to guides&lt;/a&gt;: how to provision specific resources with the Google Cloud provider&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt;: ask Pulumi Neo to help you with your project&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="upgrading"&gt;Upgrading&lt;/h3&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/registry/packages/gcp/how-to-guides/10-0-migration/"&gt;migration guide&lt;/a&gt; accounts for every resource, type and function that changed in the new version. For the most popular resources, it gives a description of the change, a risk and impact section, a way to check whether you are affected, and step by step migration snippets.&lt;/p&gt;
&lt;h3 id="use-an-agent-to-assist-with-your-upgrade"&gt;Use an agent to assist with your upgrade&lt;/h3&gt;
&lt;p&gt;We have updated the &lt;code&gt;provider-upgrade&lt;/code&gt; skill in &lt;a href="https://www.pulumi.com/blog/pulumi-agent-skills/"&gt;Pulumi Agent Skills&lt;/a&gt; to cover the upgrade from v9. You can use it from &lt;a href="https://www.pulumi.com/docs/ai/neo/"&gt;Pulumi Neo&lt;/a&gt; or from any popular coding agent. Before it bumps the provider, it scans your stack and code for the changes that affect you, and it stops to ask before anything that would replace or delete live infrastructure. Then it upgrades the dependency, runs &lt;code&gt;pulumi preview&lt;/code&gt; until the diff is explained, and leaves &lt;code&gt;pulumi up&lt;/code&gt; to you.&lt;/p&gt;
&lt;p&gt;In Neo, ask: &amp;ldquo;Upgrade this project to pulumi-gcp v10.&amp;rdquo; Neo picks the &lt;code&gt;provider-upgrade&lt;/code&gt; skill for you; there is nothing to install or name.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/gcp-v10-release/migration-prompt.png" alt="Neo task prompt asking to upgrade the project to pulumi-gcp v10, with the stack and repository attached"&gt;&lt;/p&gt;
&lt;p&gt;Neo plans the upgrade, starting with a scan of your stack while it is still on v9.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/gcp-v10-release/neo-plan.png" alt="Neo&amp;rsquo;s plan: verify the v9 baseline and scan state, bump pulumi-gcp to v10, fix SecretVersion, typecheck and preview, create a pull request"&gt;&lt;/p&gt;
&lt;p&gt;Before it edits any code, it tells you which resources are affected and what could be replaced, and waits for your answer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/gcp-v10-release/neo-risk-gate.png" alt="Neo reporting that only SecretVersion is affected, with the fix for each resource, and asking to proceed"&gt;&lt;/p&gt;
&lt;p&gt;Finally, Neo opens a pull request with the changes and the preview results. You review it and run &lt;code&gt;pulumi up&lt;/code&gt; when you are ready.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/gcp-v10-release/neo-pr.png" alt="Pull request opened by Neo changing secretDataWoVersion to a string and bumping @pulumi/gcp to 10.0.0"&gt;&lt;/p&gt;
&lt;p&gt;In Claude Code, add the Pulumi marketplace and install the &lt;code&gt;pulumi&lt;/code&gt; plugin:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/plugin marketplace add pulumi/agent-skills
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/plugin install pulumi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then ask: &amp;ldquo;Upgrade this project to pulumi-gcp v10.&amp;rdquo; You can also run &lt;code&gt;/provider-upgrade&lt;/code&gt; directly.&lt;/p&gt;
&lt;p&gt;In OpenAI Codex, register the marketplace:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;codex plugin marketplace add pulumi/agent-skills
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then run &lt;code&gt;codex&lt;/code&gt;, open &lt;code&gt;/plugins&lt;/code&gt;, and install &lt;code&gt;pulumi&lt;/code&gt;. Ask Codex to upgrade the provider to v10, or invoke the skill with &lt;code&gt;$provider-upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Pi, and in any other agent that supports the &lt;a href="https://agentskills.io"&gt;Agent Skills&lt;/a&gt; standard, install the skill with the universal installer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npx skills add pulumi/agent-skills/pulumi --skill provider-upgrade -a pi
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then ask Pi to upgrade the provider to v10, or trigger the skill with &lt;code&gt;/skill:provider-upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="why-upgrade"&gt;Why upgrade&lt;/h3&gt;
&lt;p&gt;Moving to the latest version means you keep getting the latest updates from Google Cloud. GCP is covered by our &lt;a href="https://www.pulumi.com/docs/support/provider-support-policy/"&gt;provider support policy&lt;/a&gt;: with this release, v9 receives security updates for up to 12 months (or until v11 ships), while new features, bug fixes, and upstream updates land only in v10.&lt;/p&gt;
&lt;p&gt;Staying on the latest version also means you keep getting new features. Google Cloud offers capabilities you will not find on other clouds, such as TPUs, accelerators Google designed for training and serving AI models. For example, here is how you could create a &lt;a href="https://docs.cloud.google.com/tpu/docs/v6e"&gt;Cloud TPU v6e (Trillium)&lt;/a&gt; slice with the new major version, using &lt;a href="https://www.pulumi.com/registry/packages/gcp/api-docs/tpu/v2vm/"&gt;&lt;code&gt;gcp.tpu.V2Vm&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp,java,yaml" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;gcp&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/gcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;gcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;V2Vm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;trillium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east1-d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;runtimeVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;v2-alpha-tpuv6e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;acceleratorConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;V6E&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;topology&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2x4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;schedulingConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;spot&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;workload&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tpuName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tpuWorkers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;networkEndpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eps&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ep&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_gcp&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;gcp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;tpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gcp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V2Vm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;trillium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;zone&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;us-east1-d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;runtime_version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;v2-alpha-tpuv6e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accelerator_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;V6E&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;topology&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2x4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scheduling_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;spot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;workload&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;tpu_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;tpu_workers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;network_endpoints&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ip_address&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ep&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi-gcp/sdk/v10/go/gcp/tpu&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;github.com/pulumi/pulumi/sdk/v3/go/pulumi&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewV2Vm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;trillium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;V2VmArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;us-east1-d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RuntimeVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;v2-alpha-tpuv6e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;AcceleratorConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;V2VmAcceleratorConfigArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;V6E&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Topology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;2x4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SchedulingConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;V2VmSchedulingConfigArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Spot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringMap&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;workload&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tpuName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tpuWorkers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NetworkEndpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ApplyT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;V2VmNetworkEndpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;IpAddress&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ips&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}).(&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringArrayOutput&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Pulumi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Gcp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gcp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Deployment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tpu&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V2Vm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;trillium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Zone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;us-east1-d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RuntimeVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;v2-alpha-tpuv6e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AcceleratorConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V2VmAcceleratorConfigArgs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;V6E&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Topology&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;2x4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SchedulingConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Gcp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;V2VmSchedulingConfigArgs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Spot&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Labels&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;workload&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;training&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [&amp;#34;tpuName&amp;#34;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [&amp;#34;tpuWorkers&amp;#34;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NetworkEndpoints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IpAddress&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="java" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;myproject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.pulumi.Pulumi&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.pulumi.gcp.tpu.V2Vm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.pulumi.gcp.tpu.V2VmArgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.pulumi.gcp.tpu.inputs.V2VmAcceleratorConfigArgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.pulumi.gcp.tpu.inputs.V2VmSchedulingConfigArgs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;java.util.stream.Collectors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;V2Vm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;trillium&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;V2VmArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;us-east1-d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;runtimeVersion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;v2-alpha-tpuv6e&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;acceleratorConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V2VmAcceleratorConfigArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;V6E&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;topology&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;2x4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;schedulingConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V2VmSchedulingConfigArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;spot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;workload&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tpuName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;tpuWorkers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tpu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;networkEndpoints&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;applyValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ipAddress&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="na"&gt;orElse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Collectors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="p"&gt;())));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# A Cloud TPU v6e (Trillium) slice with 8 chips, on Spot capacity.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;trillium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;gcp:tpu:V2Vm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-east1-d&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runtimeVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v2-alpha-tpuv6e&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;acceleratorConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;V6E&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;topology&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;2x4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;schedulingConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;spot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;workload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;training&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tpuName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${trillium.name}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tpuWorkers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${trillium.networkEndpoints}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://cloud.google.com/products/gemini-enterprise-agent-platform"&gt;Gemini Enterprise Agent Platform (formerly Vertex AI)&lt;/a&gt;, Google&amp;rsquo;s platform for building with Gemini models, also gets new resources. New in v10, &lt;a href="https://www.pulumi.com/registry/packages/gcp/api-docs/vertex/airagcorpus/"&gt;&lt;code&gt;gcp.vertex.AiRagCorpus&lt;/code&gt;&lt;/a&gt; brings its RAG Engine under Pulumi: declare the corpus that grounds your Gemini applications in your own documents, with its embedding model and vector store, in the same program as the rest of your infrastructure. It joins the &lt;a href="https://www.pulumi.com/registry/packages/gcp/api-docs/vertex/aireasoningengine/"&gt;Agent Runtime&lt;/a&gt; and &lt;a href="https://www.pulumi.com/registry/packages/gcp/api-docs/vertex/aimodelgardenenablemodel/"&gt;Model Garden&lt;/a&gt; resources added during v9. In the provider, these resources keep the &lt;code&gt;gcp.vertex&lt;/code&gt; module name.&lt;/p&gt;
&lt;p&gt;You can find more about this release in the &lt;a href="https://github.com/pulumi/pulumi-gcp/releases/tag/v10.0.0"&gt;v10 release notes&lt;/a&gt;. We hope your transition goes smoothly, and as always we are happy to hear your feedback in our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt; or through &lt;a href="https://www.pulumi.com/support/"&gt;support&lt;/a&gt; if you are a paying Pulumi customer. Happy hacking!&lt;/p&gt;</description><author>Alberto Pose</author><category>google-cloud</category><category>releases</category><category>features</category></item><item><title>Change your components, keep your infrastructure</title><link>https://www.pulumi.com/blog/component-state-migrations/</link><pubDate>Fri, 25 Sep 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/component-state-migrations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/component-state-migrations/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/iac/concepts/components/"&gt;Components&lt;/a&gt; let you turn a group of resources into a reusable building block. You can define a network, a database, or an application service once and share it across projects and teams. People using the component work with its inputs and outputs without needing to understand every resource inside it.&lt;/p&gt;
&lt;p&gt;Suppose you built your network with the legacy AWSX VPC component. It manages the VPC, subnets, route tables, and gateways behind a few lines of code. Now you want to upgrade to the modern AWSX component. Later, your needs change again: you want more control over the resources than the component gives you. At each step, the network is already running. You want to change the code that manages it without rebuilding the network itself.&lt;/p&gt;
&lt;p&gt;Pulumi&amp;rsquo;s new component state migrations let you ship the upgrade path with the component itself. A migration translates the saved state of a component and its children before Pulumi works out which resources need to change. Component authors can change the internal design and include the migration in the same release.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;&lt;p&gt;The state migrations API is experimental and may change.&lt;/p&gt;
&lt;p&gt;Share feedback in the &lt;a href="https://github.com/pulumi/pulumi/discussions/24799"&gt;component state migrations discussion&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="one-vpc-three-versions-of-the-code"&gt;One VPC, three versions of the code&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/pulumi/examples/tree/master/aws-ts-awsx-vpc-state-migration"&gt;AWSX VPC example&lt;/a&gt; follows a network as your needs change over time. You start with v1, upgrade to v2, and later move to v3. Each version builds on the infrastructure already running.&lt;/p&gt;
&lt;p&gt;You start with the legacy &lt;code&gt;awsx.classic.ec2.Vpc&lt;/code&gt; component. This first version creates a VPC with one isolated subnet, a route table and its association, and an internet gateway. A security group sits outside the component and refers to the VPC.&lt;/p&gt;
&lt;p&gt;Without a migration that connects the old state to the new code, an upgrade could replace the VPC instead of keeping it. That change would reach beyond the component: the security group refers to the VPC&amp;rsquo;s ID, so a new VPC would mean &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-resource-ec2-securitygroup.html#cfn-ec2-securitygroup-vpcid"&gt;replacing the security group too&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now imagine a production database using that network and security group. The example does not create a database, but in a real application, changes to its network can cause downtime or require more resource replacements. If the database itself has to be recreated, its replacement does not automatically contain the old data. Without a backup or a data migration, deleting the old database could mean losing that data. You do not want a component upgrade to turn into a database recovery job.&lt;/p&gt;
&lt;p&gt;After running this network for a while, you decide to upgrade to the modern &lt;code&gt;awsx.ec2.Vpc&lt;/code&gt; component. The second version makes that change while keeping your existing network.&lt;/p&gt;
&lt;p&gt;Further down the road, suppose the modern component no longer fits your needs. You want to define and configure each resource yourself. The third version removes AWSX and declares the resources directly with &lt;code&gt;@pulumi/aws&lt;/code&gt;. Pulumi still manages them, but your code now controls each resource instead of relying on the component to create it.&lt;/p&gt;
&lt;p&gt;Across all three versions, the AWS resource IDs stay the same. The security group continues to use the same VPC. What changes is how Pulumi records those resources and their relationships.&lt;/p&gt;
&lt;p&gt;These trees show the resources Pulumi tracks in each version. The security group is outside the VPC tree and is omitted here. The &lt;code&gt;awsx:&lt;/code&gt; entries are component records; the &lt;code&gt;aws:&lt;/code&gt; entries represent the AWS resources that stay in place.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v1: awsx:x:ec2:Vpc &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── aws:ec2/vpc:Vpc &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── awsx:x:ec2:Subnet &amp;#34;vpc-isolated-0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├── aws:ec2/subnet:Subnet &amp;#34;vpc-isolated-0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├── aws:ec2/routeTable:RouteTable &amp;#34;vpc-isolated-0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └── aws:ec2/routeTableAssociation:RouteTableAssociation &amp;#34;vpc-isolated-0&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── awsx:x:ec2:InternetGateway &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── aws:ec2/internetGateway:InternetGateway &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v2: awsx:ec2:Vpc &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── aws:ec2/vpc:Vpc &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── aws:ec2/subnet:Subnet &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └── aws:ec2/routeTable:RouteTable &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └── aws:ec2/routeTableAssociation:RouteTableAssociation &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── aws:ec2/internetGateway:InternetGateway &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;v3: aws:ec2/vpc:Vpc &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── aws:ec2/subnet:Subnet &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └── aws:ec2/routeTable:RouteTable &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └── aws:ec2/routeTableAssociation:RouteTableAssociation &amp;#34;vpc-isolated-1&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── aws:ec2/internetGateway:InternetGateway &amp;#34;vpc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="why-a-change-in-code-needs-a-change-in-state"&gt;Why a change in code needs a change in state&lt;/h2&gt;
&lt;p&gt;Pulumi&amp;rsquo;s state records both the physical resources and the components that group them. Each record has a Pulumi name, called a URN. Managed resources also have an ID from the cloud provider, such as an AWS VPC ID.&lt;/p&gt;
&lt;p&gt;Legacy and modern AWSX organize their resources differently. The legacy component wraps the subnet and internet gateway in separate components. Modern AWSX removes those wrappers and puts the managed resources under different parents. In this example, the Pulumi name of the subnet also changes from &lt;code&gt;vpc-isolated-0&lt;/code&gt; to &lt;code&gt;vpc-isolated-1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/options/aliases/"&gt;Aliases&lt;/a&gt; handle changes to a resource&amp;rsquo;s name, type, or parent when its saved state remains compatible. This upgrade also needs to remove component wrappers and transfer references to the resources that take their place. A state migration describes that whole change together.&lt;/p&gt;
&lt;h2 id="the-first-migration-from-legacy-to-modern-awsx"&gt;The first migration: from legacy to modern AWSX&lt;/h2&gt;
&lt;p&gt;To move your existing network to modern AWSX, you register the new VPC component with an alias for the legacy component type and a migration callback through the &lt;code&gt;stateMigrations&lt;/code&gt; option. This excerpt from the example shows the registration. &lt;code&gt;migrateClassicVpc&lt;/code&gt; comes from the example&amp;rsquo;s &lt;a href="https://github.com/pulumi/examples/blob/master/aws-ts-awsx-vpc-state-migration/v2/migration.ts"&gt;migration file&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;awsx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;vpc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;availabilityZoneNames&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;availabilityZone&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cidrBlock&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;enableDnsHostnames&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;enableDnsSupport&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;instanceTenancy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;natGateways&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;strategy&lt;/span&gt;: &lt;span class="kt"&gt;awsx.ec2.NatGatewayStrategy.None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;subnetStrategy&lt;/span&gt;: &lt;span class="kt"&gt;awsx.ec2.SubnetAllocationStrategy.Legacy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;subnetSpecs&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;awsx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SubnetType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Isolated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cidrMask&lt;/span&gt;: &lt;span class="kt"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;: &lt;span class="kt"&gt;vpcTags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;aliases&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;awsx:x:ec2:Vpc&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;stateMigrations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;migrateClassicVpc&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The alias lets Pulumi find the old component. The callback then receives its saved state, followed by the state of its children. It copies those records, changes their names and parents to match modern AWSX, and returns two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;newState&lt;/code&gt;: the complete set of records that should replace the old component and its children.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;successors&lt;/code&gt;: a map from each old URN that disappears to the URN that takes its place.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;migrateClassicVpc&lt;/span&gt;: &lt;span class="kt"&gt;pulumi.StateMigration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oldState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldRoot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;oldState&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;modernVpcType&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;oldRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;awsVpcType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;classicVpcType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`Unexpected VPC type: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;oldRoot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...find the old records and calculate the new URNs...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newSubnet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldSubnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newSubnetUrn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newVpcUrn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...copy and rename the other retained records...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newRoot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newVpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newSubnet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newRouteTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newRouteTableAssociation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;newInternetGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;oldSubnetComponentUrn&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newSubnetUrn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resourceUrn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldSubnet&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newSubnetUrn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ...map the other old URNs to their successors...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="https://github.com/pulumi/examples/blob/master/aws-ts-awsx-vpc-state-migration/v2/migration.ts"&gt;Full migration code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The first checks make the callback safe to run again: if the state already uses modern AWSX or plain AWS resources, there is nothing to do. An unexpected component type raises an error instead of guessing how to migrate it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;rename&lt;/code&gt; helper copies the saved record and changes its URN, type, and parent. It preserves the AWS resource ID and the other saved fields. Here, it moves the subnet under the managed VPC.&lt;/p&gt;
&lt;p&gt;The two subnet entries in &lt;code&gt;successors&lt;/code&gt; let the Pulumi engine know that the old component wrapper and the managed subnet point to the same new subnet record. Pulumi uses these mappings to update dependencies and resource references elsewhere in the stack. For example, the security group lives outside the VPC component, but its reference to the VPC still needs to be valid after the migration. The VPC successor mapping keeps that reference connected to the migrated VPC record, which retains the same AWS VPC ID.&lt;/p&gt;
&lt;h2 id="the-second-migration-from-awsx-to-plain-aws-resources"&gt;The second migration: from AWSX to plain AWS resources&lt;/h2&gt;
&lt;p&gt;You have been running v2 for a while when a new requirement calls for a subnet or routing layout that the modern component does not support. You decide to manage those choices in your own code. The third version declares the VPC, subnet, route table, association, and internet gateway directly with &lt;code&gt;@pulumi/aws&lt;/code&gt;. This migration changes who defines those resources in your program; you can then adjust their configuration in a separate update.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/pulumi/examples/blob/master/aws-ts-awsx-vpc-state-migration/v3/migration.ts"&gt;second migration&lt;/a&gt; removes the AWSX VPC component record and moves the managed VPC into its place. Both the old component and its VPC child map to the new VPC record. The VPC keeps its AWS ID, and the other resources remain beneath it.&lt;/p&gt;
&lt;p&gt;The VPC registration keeps aliases for both previous component types and both migration callbacks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;vpc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ec2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Vpc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;vpc&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;cidrBlock&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;10.0.0.0/16&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;enableDnsHostnames&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;enableDnsSupport&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;instanceTenancy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;default&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tags&lt;/span&gt;: &lt;span class="kt"&gt;vpcTags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;aliases&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;awsx:x:ec2:Vpc&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kr"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;awsx:ec2:Vpc&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;stateMigrations&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;migrateClassicVpc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;migrateAwsxVpc&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pulumi runs the callbacks in order, passing each result to the next callback. A stack still using legacy AWSX can upgrade directly to the plain AWS version. A stack already using modern AWSX skips the first migration. Once both migrations have run, both callbacks return no result on later updates.&lt;/p&gt;
&lt;p&gt;Keeping earlier migrations with the component means its users can skip versions without having to edit stack state by hand.&lt;/p&gt;
&lt;h2 id="check-the-upgrade-before-applying-it"&gt;Check the upgrade before applying it&lt;/h2&gt;
&lt;p&gt;A migration changes saved state. Afterward, Pulumi compares the new program with that state and calls the provider for any remaining changes. Keeping resource IDs does not mean every upgrade has an empty preview: this example can still show in-place updates for provider defaults and tags.&lt;/p&gt;
&lt;p&gt;To try the example, start with &lt;code&gt;v1&lt;/code&gt; and follow its README. Use the same stack, backend, project name, AWS region, and availability zone for each version.&lt;/p&gt;
&lt;p&gt;Before each upgrade, run &lt;code&gt;pulumi preview&lt;/code&gt;. The existing VPC, subnet, route table, association, internet gateway, and security group should have no creates, deletes, or replacements. Review any in-place changes before running &lt;code&gt;pulumi up&lt;/code&gt;. Preview evaluates the migration without saving it, and the update saves the migrated state.&lt;/p&gt;
&lt;h2 id="ship-the-migration-with-your-component"&gt;Ship the migration with your component&lt;/h2&gt;
&lt;p&gt;If you maintain a component, register the migration inside its implementation and ship both together. Users do not need to write the migration, attach the callback, or edit their stack state. When they upgrade the component and run Pulumi, it runs the migration as part of the normal preview and update.&lt;/p&gt;
&lt;p&gt;For an internal change that keeps the same component inputs and outputs, users can keep their existing component calls. They do not need to know which resources moved or how the saved state changed. They still review the preview, as with any upgrade, but the component handles the migration details.&lt;/p&gt;
&lt;p&gt;That makes the upgrade path part of the reusable building block. You write and test it once, and each team using the component gets it with the new version.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/iac/guides/building-extending/components/state-migrations/"&gt;component state migrations guide&lt;/a&gt; covers the callback contract. The &lt;a href="https://github.com/pulumi/examples/tree/master/aws-ts-awsx-vpc-state-migration"&gt;VPC example&lt;/a&gt; contains all three programs and the migration code shown here.&lt;/p&gt;</description><author>Julien Poissonnier</author><category>components</category><category>migration</category><category>infrastructure-as-code</category></item><item><title>Set Up Cloud OIDC From the Pulumi CLI</title><link>https://www.pulumi.com/blog/esc-oidc-setup-cli/</link><pubDate>Fri, 11 Sep 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/esc-oidc-setup-cli/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-oidc-setup-cli/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/guides/configuring-oidc/"&gt;Pulumi ESC can act as an OpenID Connect (OIDC) provider&lt;/a&gt; for AWS, Azure, and Google Cloud, issuing short-lived, signed tokens that these clouds exchange for temporary credentials. This eliminates hard-coded credentials and improves your security posture.&lt;/p&gt;
&lt;p&gt;Last year, we introduced an onboarding flow in the Pulumi Cloud console that makes it super easy to configure OIDC for your cloud provider in a few guided steps.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/#meeting-agents-where-they-work-the-cli"&gt;bringing Pulumi Cloud into the CLI&lt;/a&gt; so agents can use its capabilities directly from the terminal, without requiring a human to complete steps in the console. The new &lt;code&gt;pulumi env setup&lt;/code&gt; command brings OIDC onboarding to that workflow, with interactive prompts for guided setup and non-interactive flags for scripts and agents.&lt;/p&gt;
&lt;h2 id="pulumi-env-setup---how-it-works"&gt;&lt;code&gt;pulumi env setup&lt;/code&gt; - how it works&lt;/h2&gt;
&lt;p&gt;Run the command with your desired cloud provider (&lt;code&gt;aws&lt;/code&gt;, &lt;code&gt;azure&lt;/code&gt;, &lt;code&gt;gcp&lt;/code&gt;). For example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi env setup aws
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command then asks what it needs to configure your cloud, including your credentials, the accounts to configure, and the level of access. The questions differ per cloud.&lt;/p&gt;
&lt;p&gt;For AWS, it asks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How to authenticate to AWS. It uses the credentials you already have, or it signs you in with AWS SSO.&lt;/li&gt;
&lt;li&gt;Which accounts to configure.&lt;/li&gt;
&lt;li&gt;Which policy to attach to the OIDC role. Choose &lt;code&gt;AdministratorAccess&lt;/code&gt; for Pulumi Deployments, &lt;code&gt;ReadOnlyAccess&lt;/code&gt; for Pulumi Insights, or any other policy ARN.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then, it will print out the plan:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;About to configure OIDC for organization my-org:
account 111111111111:
create role pulumi-esc-oidc-622e86ea-319ba4c675bb3c00-role
attach arn:aws:iam::aws:policy/AdministratorAccess
create ESC environment my-org/aws-login/sandbox-account-env
Proceed? [yes/no]
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After you confirm, the command creates the identity provider, the IAM role, and the policy attachment in each account. It then creates one ESC Environment per account, with the &lt;code&gt;aws-login&lt;/code&gt; provider already configured.&lt;/p&gt;
&lt;h3 id="non-interactive-setup"&gt;Non-interactive setup&lt;/h3&gt;
&lt;p&gt;You can also run the command without interactive prompts by passing in the necessary flags. Each cloud has its own flags, so be sure to check &lt;code&gt;pulumi env setup &amp;lt;cloud&amp;gt; --help&lt;/code&gt;. Running non-interactively is great for automated use cases or agents!&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi env setup aws &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --account &lt;span class="m"&gt;111111111111&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy AdministratorAccess &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --project my-project &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi env setup&lt;/code&gt; ships with the latest Pulumi CLI. To configure your first cloud:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authenticate to Pulumi Cloud with &lt;code&gt;pulumi login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi env setup aws&lt;/code&gt;, &lt;code&gt;pulumi env setup azure&lt;/code&gt;, or &lt;code&gt;pulumi env setup gcp&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;See the &lt;a href="https://www.pulumi.com/docs/esc/guides/configuring-oidc/"&gt;OIDC configuration docs&lt;/a&gt; to learn more about using OIDC with Pulumi, and the &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC docs&lt;/a&gt; to explore what you can do with ESC.&lt;/p&gt;</description><author>Sean Yeh</author><category>esc</category><category>pulumi-cli</category><category>security</category></item><item><title>Pulumi Kubernetes v4.34.0: CRDs as provider extensions</title><link>https://www.pulumi.com/blog/kubernetes-crds-as-provider-extensions/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/kubernetes-crds-as-provider-extensions/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/kubernetes-crds-as-provider-extensions/index.png" /&gt;
&lt;p&gt;We&amp;rsquo;re really excited to bring you v4.34.0, the newest version of the &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;Pulumi Kubernetes provider&lt;/a&gt;, which includes improved support for Kubernetes Custom Resource Definitions (CRDs).
As with any release, we&amp;rsquo;ve also shipped standard dependency updates and bug fixes.
This provider release includes the newest resources for Kubernetes v1.37.0, which was recently cut.
So that in itself is very exciting!&lt;/p&gt;
&lt;p&gt;But the feature we&amp;rsquo;re proudest of is that you can now &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/typed-customresources-with-provider-extensions/"&gt;extend the Kubernetes provider with any Kubernetes Custom Resource Definition of your choice&lt;/a&gt; by passing its manifest file to Pulumi, using the new &lt;code&gt;--extension&lt;/code&gt; flag.
We believe first-class CRD support in Pulumi is becoming more important than ever.
For example, since the retirement of the ingress-nginx controller earlier this year, the recommended path for cluster ingress is Gateway API, which is maintained and shipped as CRDs.&lt;/p&gt;
&lt;h2 id="generating-a-pulumi-sdk-for-crds"&gt;Generating a Pulumi SDK for CRDs&lt;/h2&gt;
&lt;p&gt;In your Pulumi project root, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi package add kubernetes --extension &lt;span class="s2"&gt;&amp;#34;name=gateway-networking crd-manifest=gateway-api-crds.yaml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You will see the custom SDK appear in a new &lt;code&gt;sdks/&lt;/code&gt; folder, as well as a new parameterization reference in &lt;code&gt;Pulumi.yaml&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="single-provider-instance"&gt;Single provider instance&lt;/h2&gt;
&lt;p&gt;Your new CRD schema exists as an extension to your existing provider and will be managed under the same provider instance, allowing you to use a single provider configuration and kubeconfig.&lt;/p&gt;
&lt;h2 id="sdks-as-dependencies"&gt;SDKs as dependencies&lt;/h2&gt;
&lt;p&gt;Additionally, your code no longer needs to ship SDK files as part of the project.
The provider extension is referenced in your project file and its SDK, like all dependencies, can be regenerated via &lt;code&gt;pulumi install&lt;/code&gt;.
You can choose to version the extension SDK, or continue to check the files into version control if you so desire.&lt;/p&gt;
&lt;h2 id="full-language-support-including-for-yaml"&gt;Full language support, including for YAML&lt;/h2&gt;
&lt;p&gt;Kubernetes CRDs can now be provisioned with Pulumi in all supported languages.&lt;/p&gt;
&lt;h2 id="unified-cli-experience"&gt;Unified CLI experience&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi package add --extension&lt;/code&gt; extends your CRD schema into the Pulumi Kubernetes provider, using the same CLI as any other Pulumi operation.
It generates validated, schematized types that will be discoverable with autocomplete tools in your codebase.&lt;/p&gt;
&lt;h2 id="migration-from-crd2pulumi"&gt;Migration from crd2pulumi&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;ve been using &lt;code&gt;crd2pulumi&lt;/code&gt; in the past, pivoting to using the new provider extension is possible by referencing the new SDK package name in your Pulumi program, without any changes to your stack state.
Migrating should result in a seamless no-op on &lt;code&gt;pulumi up&lt;/code&gt;.
Read more in &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/typed-customresources-with-provider-extensions/#migrating-from-crd2pulumi"&gt;Migrating from crd2pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Available from Pulumi v3.255.0 and the Pulumi Kubernetes provider v4.34.0.&lt;/p&gt;</description><author>Guinevere Saenger</author><category>kubernetes</category><category>releases</category><category>providers</category></item><item><title>Neo Security: Securing Infrastructure in the Agentic Era</title><link>https://www.pulumi.com/blog/pulumi-neo-security/</link><pubDate>Fri, 28 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-neo-security/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-neo-security/index.png" /&gt;
&lt;p&gt;Recently, AI systems have started turning up exploitable flaws in code that survived
decades of human review. The frontier labs have released useful tools to help uncover
many of these flaws through agent-led static code analysis.&lt;/p&gt;
&lt;p&gt;This is a huge leap ahead, but cloud infrastructure has many exploitable flaws that code
analysis alone cannot find. These flaws are often as severe as the ones in code, or
worse, and they await discovery by malicious agents on offense. We realized recently we
can uniquely help here. At Pulumi, we have complete visibility into your entire cloud estate:
infrastructure resources, their semantics, connections and dependencies between them,
runtime logs and information, and more — and have built an entire context graph out of
them that is accessible to agents.&lt;/p&gt;
&lt;p&gt;Thanks to large language models, the cost of analyzing that full context graph is no longer prohibitive.
As a result, today we&amp;rsquo;re opening a research preview of &lt;strong&gt;Pulumi Neo Security&lt;/strong&gt;. Neo Security
is an agent that can find exploitable flaws in your cloud infrastructure. It starts with a threat model of your cloud estate, and then works
systematically through every potential point of attack. The result is a security posture
report that is immediately actionable thanks to Pulumi&amp;rsquo;s infrastructure as code technology.&lt;/p&gt;
&lt;p&gt;Neo Security works on your existing infrastructure regardless of how it was provisioned, across
any of our thousands of cloud providers including AWS, Azure, Google Cloud, and
Kubernetes.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re releasing it in research preview to begin, so we can work closely with customers to
run and address any findings. If you&amp;rsquo;d like to give it a try, &lt;a href="https://www.pulumi.com/contact/"&gt;contact us&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="how-it-finds-attack-paths"&gt;How it finds attack paths&lt;/h2&gt;
&lt;p&gt;Neo Security&amp;rsquo;s aim is to provide a high-confidence, actionable security posture report.
It gets there in three passes.&lt;/p&gt;
&lt;p&gt;The first builds a threat model, before it looks for anything. It works out what your
crown jewels are, which resources are accessible to outside actors, which accounts hold
production data, where the trust boundaries sit between the internet, your workloads, and
the identities those workloads carry, and which attackers are realistic for your
organization. That is what gives it relative risk and blast radius. Without it, a
development sandbox would be treated the same as a production database.&lt;/p&gt;
&lt;p&gt;Working from that model, the second pass maps attack vectors: internet entry points,
federation and trust relationships, workload identity, lateral movement between accounts,
data and secret reachability, and the ways those combine. A resource matters only insofar
as an attacker can use it. The goal is to find, for each misconfiguration, the worst
outcome it enables.&lt;/p&gt;
&lt;p&gt;The third pulls together six planes of evidence at once, each living in a different
system:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resource inventory.&lt;/strong&gt; The discovered infrastructure inventory across all cloud accounts,
regions, and resource types. For example: AWS S3 buckets and EC2 VMs, GKE clusters and
the Kubernetes resources within them, Azure functions, Cloudflare CDNs, Snowflake data
warehouses, and even hybrid and private cloud resources. This includes resources provisioned outside of IaC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The reference graph.&lt;/strong&gt; This tells Neo which workload carries which identity, which identity reaches
which data, and which stack manages which discovered resource. Neo Security reads this
plane through the &lt;a href="https://www.pulumi.com/blog/pulumi-context-api/"&gt;Context API&lt;/a&gt; we shipped earlier this
week: a single query walks relationships across the estate and returns every result
with the path that reached it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intent.&lt;/strong&gt; When available, Neo reads the infrastructure code that
created a resource, whether Pulumi or Terraform IaC, for the semantics a cloud API doesn&amp;rsquo;t
know about: comments surrounding resources, the resource declarations and relationships,
logic and naming, code commit and review history, and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime state.&lt;/strong&gt; Information that isn&amp;rsquo;t statically known from code and
infrastructure metadata. This includes logs and metrics, uptime information and boot logs
for servers, network traffic, and more. This is enabled by Neo having access to any tools
a platform engineer would.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policy and compliance results.&lt;/strong&gt; Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/product/discovery-governance/"&gt;discovery and
governance&lt;/a&gt; capabilities ship over 150 built-in
policies, many of them security rules, mapped to CIS Controls, NIST SP 800-53,
HITRUST CSF, and PCI DSS. Enterprises can also write their own. Neo Security uses
existing scanned resources and their violations as well as the policy definitions
to discover potential risks in the infrastructure beyond known violations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The provider&amp;rsquo;s own answers.&lt;/strong&gt; Some questions configuration cannot settle, so Neo
asks the cloud directly: Access Analyzer for external reachability, public-access checks
on storage, and policy simulation for whether a principal can actually perform an
action. This is what resolves the permissions and firewall rules that survive once every
overlapping rule, boundary, and service control policy has been applied.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neo uses this information to build a model of your estate and home in on validated paths.
It proves or refutes each attack vector, then ranks what survives by severity and
confidence. The result is a short list, each entry carrying its evidence and, where source
is available, a fix as specific lines of code. The analysis deeply understands each cloud&amp;rsquo;s identity model, networking, and data services
well enough to resolve effective permissions and firewall rules and to ask the providers
directly. The assessment phase is read-only throughout.&lt;/p&gt;
&lt;h2 id="findings-become-pull-requests"&gt;Findings become pull requests&lt;/h2&gt;
&lt;p&gt;Most security tools stop at telling you something is wrong, which leaves the hardest part
— remediation — as an exercise for the reader. Pulumi already declares and applies
infrastructure change, so a proven finding becomes a proposed diff, a preview of what
would change, and a pull request for a person to review. Remediation is the only part that
writes anything, and only ever a proposed change in a repository, with deployment left to
your existing reviewed workflow.&lt;/p&gt;
&lt;h2 id="what-a-report-looks-like"&gt;What a report looks like&lt;/h2&gt;
&lt;p&gt;We have worked with several teams to run Neo Security against real production estates of different shapes and
maturity, and it repeatedly found critical vulnerabilities the owners did not know
existed. A single run reconciles thousands of managed resources against the account&amp;rsquo;s
discovered inventory across every region in use.&lt;/p&gt;
&lt;p&gt;Here are example findings, anonymized and generalized from real runs:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Finding&lt;/th&gt;
&lt;th&gt;Severity&lt;/th&gt;
&lt;th&gt;Confidence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Deployment federation role grants administrator access with no subject-claim condition&lt;/td&gt;
&lt;td&gt;critical&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Build role trusts source-control OIDC with a wildcard on the branch claim&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Build policy grants &lt;code&gt;iam:AttachRolePolicy&lt;/code&gt; on every role in the account&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Test Kubernetes cluster API endpoint reachable from any address&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Security groups named for production allow all TCP and SSH from &lt;code&gt;0.0.0.0/0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Public compute instance with IMDSv1 and suspected secrets in user data&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Load balancer HTTP listener forwards API requests without enforcing TLS&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;CDN connects to its origin over HTTP-only, exposing auth headers in transit&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Static access key for the mail-sending user, unrotated for over a year&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Mail-sending policy allows send-as on any verified identity&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Database snapshot shared with an account outside the organization&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Analytics tool auto-provisions any account on the corporate domain&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;No management-plane audit trail defined in IaC&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;No WAF on the internet-facing load balancer or CDN&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The implications of these example findings range from complete production account take-over, to
poor encryption practices that put sensitive data at risk, to improperly authenticated
email services that could be abused for phishing campaigns, to static unrotated keys that
leave the account open to risks should it leak, and many other unfortunate outcomes. Each
comes with a severity and risk so you can prioritize accordingly, and Neo works to exclude
disproven findings and those without consequence.&lt;/p&gt;
&lt;h2 id="getting-a-scan"&gt;Getting a scan&lt;/h2&gt;
&lt;p&gt;We have been impressed what the combination of the latest frontier models, the unique context
Pulumi has across several dimensions of your infrastructure, and giving the agent deep security
domain expertise have been able to produce. We hope it helps the world of infrastructure get more secure.&lt;/p&gt;
&lt;p&gt;Pulumi Neo Security is open now to a small group of invited customers, and the initial scan
is free during the research preview. We&amp;rsquo;re looking for estates with real complexity and risk:
multi-cloud and multi-account, a good mix of resource types, IaC and non-IaC resources,
and those for which their infrastructure security is paramount.&lt;/p&gt;
&lt;p&gt;Attackers are going to point agents at cloud infrastructure next. We would rather you find
these problems first and we want to help. If you want to try a scan, &lt;a href="https://www.pulumi.com/contact/"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;</description><author>Joe Duffy</author><category>ai</category><category>security</category><category>pulumi-neo</category></item><item><title>Pulumi Context API: query your infrastructure as a graph</title><link>https://www.pulumi.com/blog/pulumi-context-api/</link><pubDate>Wed, 26 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-context-api/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-context-api/index.png" /&gt;
&lt;p&gt;Every platform team fields the same questions: What is running? What breaks if we change this? What can we safely delete? The answers exist, but they&amp;rsquo;re scattered across state files, cloud consoles, and the memories of whoever set things up. Today we&amp;rsquo;re launching the &lt;a href="https://www.pulumi.com/docs/discovery-governance/context-api/"&gt;Pulumi Context API&lt;/a&gt;, a read-only API that connects Pulumi-managed and discovered resources, stacks, and their relationships into a graph. It&amp;rsquo;s designed agent-first: &lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt;, our infrastructure agent, uses it out of the box, and other agents can fetch the current graph vocabulary and query guidance on demand. It&amp;rsquo;s available in public preview for organizations on the Enterprise and Business Critical editions.&lt;/p&gt;
&lt;h2 id="answers-that-follow-infrastructure-relationships"&gt;Answers that follow infrastructure relationships&lt;/h2&gt;
&lt;p&gt;Pulumi already records the resources your programs manage, their dependencies, how stacks consume each other&amp;rsquo;s outputs, and the resources &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/"&gt;Pulumi Discovery&lt;/a&gt; finds outside infrastructure as code (IaC). The Context API connects this data so you can ask questions that depend on the relationships:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Impact&lt;/strong&gt;: Which stacks are affected if we upgrade this provider? If this stack changes, what consumes its outputs?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coverage&lt;/strong&gt;: How much of our infrastructure lives outside IaC, and in which accounts?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cleanup&lt;/strong&gt;: Which stacks have no dependents and are candidates for retirement?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A query is a JSON document with a handful of clauses. &lt;code&gt;anchor&lt;/code&gt; names the starting nodes, &lt;code&gt;traverse&lt;/code&gt; follows relationships from there, and &lt;code&gt;return&lt;/code&gt; chooses what comes back. You can run a query through the Pulumi CLI or REST API. Here&amp;rsquo;s a selector that starts from AWS provider instances older than version 7.0.0 and follows incoming &lt;code&gt;provided_by&lt;/code&gt; relationships back to the visible resources they manage:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;anchor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nodeType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;resource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;match&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pulumi:providers:aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;fields&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;provider_version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;op&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;lt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;7.0.0&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;traverse&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;edgeTypes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;provided_by&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;direction&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;in&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;alias&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;managed&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;return&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;select&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;anchor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;managed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A response for one matching provider and one managed resource looks like this (abridged for clarity):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nodes&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;urn:pulumi:prod::payments::pulumi:providers:aws::default_6_0_4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nodeType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;resource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;frontier&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;anchor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;pulumi:providers:aws&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;urn:pulumi:prod::payments::aws:ec2/instance:Instance::payments-web-0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nodeType&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;resource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;frontier&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;managed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;aws:ec2/instance:Instance&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;edges&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;from&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;urn:pulumi:prod::payments::aws:ec2/instance:Instance::payments-web-0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;to&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;urn:pulumi:prod::payments::pulumi:providers:aws::default_6_0_4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;provided_by&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;pageInfo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;resultCount&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;meta&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;resultMode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;exact&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;visibility&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;complete&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;anchor&lt;/code&gt; frontier marks the provider, while &lt;code&gt;managed&lt;/code&gt; marks the EC2 instance reached by the traversal. The &lt;code&gt;provided_by&lt;/code&gt; edge keeps its defined direction from the instance to its provider, and &lt;code&gt;resultCount&lt;/code&gt; reflects the two nodes on this page. The &lt;a href="https://www.pulumi.com/docs/discovery-governance/guides/context-api/#put-the-clauses-together"&gt;Context API query guide&lt;/a&gt; walks through the complete response, and its &lt;a href="https://www.pulumi.com/docs/discovery-governance/guides/context-api/#check-completeness-before-acting"&gt;completeness guidance&lt;/a&gt; explains how to assess an answer before acting on it.&lt;/p&gt;
&lt;h2 id="ask-neo-or-bring-your-own-agent"&gt;Ask Neo or bring your own agent&lt;/h2&gt;
&lt;p&gt;Start by asking an agent a question in natural language. &lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt; uses the Context API out of the box and runs queries with the permissions of the person who invoked it.&lt;/p&gt;
&lt;p&gt;Claude Code, Cursor, Codex, and other agents that can run authenticated Pulumi CLI commands can fetch the schema endpoint&amp;rsquo;s Markdown primer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi api GetGraphQuerySchema
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The primer explains the current graph vocabulary, query grammar, engine limits, examples, pagination, and completeness checks. Put the command in your &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;CLAUDE.md&lt;/code&gt; so the agent can refresh the primer as the API evolves. The &lt;a href="https://www.pulumi.com/docs/discovery-governance/guides/context-api/"&gt;human-readable query guide&lt;/a&gt; explains the same concepts and includes direct CLI and REST examples.&lt;/p&gt;
&lt;h2 id="available-in-public-preview"&gt;Available in public preview&lt;/h2&gt;
&lt;p&gt;The Context API is available now for every organization on the Enterprise and Business Critical editions. The &lt;a href="https://www.pulumi.com/docs/discovery-governance/context-api/#get-access"&gt;&lt;code&gt;pulumi api&lt;/code&gt; access requirements&lt;/a&gt; include &lt;a href="https://www.pulumi.com/docs/install/"&gt;Pulumi CLI&lt;/a&gt; v3.243.0 or later, an authenticated session, and a role with the &lt;a href="https://www.pulumi.com/docs/administration/reference/rbac-scopes/org-settings/#resources"&gt;&lt;code&gt;resources:search&lt;/code&gt; permission&lt;/a&gt;. The default Member and Admin roles grant this permission. Pulumi Cloud &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;role-based access control&lt;/a&gt; limits responses to the resources, stacks, and cloud accounts the caller can read.&lt;/p&gt;
&lt;p&gt;During public preview, the graph vocabulary and limits may change. Fetch the &lt;a href="https://www.pulumi.com/docs/discovery-governance/guides/context-api/#get-the-deployed-schema"&gt;deployed schema&lt;/a&gt; when you need the current contract. We also plan to connect more Pulumi Cloud data, including &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environments, teams and roles, cloud accounts, and service catalog concepts from &lt;a href="https://www.pulumi.com/docs/idp/"&gt;Pulumi IDP&lt;/a&gt;. Feedback during preview will shape the relationships and data sources we add next.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Start with the &lt;a href="https://www.pulumi.com/docs/discovery-governance/context-api/"&gt;Context API overview&lt;/a&gt;, then follow the &lt;a href="https://www.pulumi.com/docs/discovery-governance/guides/context-api/#ask-questions-through-an-ai-agent"&gt;agent workflow&lt;/a&gt; to equip your agent. Ask a natural-language question such as, &amp;ldquo;Which stacks consume outputs from the &lt;code&gt;payments/prod&lt;/code&gt; stack?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Give it a try today, and share your feedback in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or through your account team.&lt;/p&gt;</description><author>Levi Blackstone</author><category>features</category><category>ai-agents</category><category>pulumi-cloud</category></item><item><title>Never Miss What Your Infrastructure Is Telling You</title><link>https://www.pulumi.com/blog/notification-center/</link><pubDate>Tue, 11 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/notification-center/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/notification-center/index.png" /&gt;
&lt;p&gt;Plenty happens in a Pulumi organization while you&amp;rsquo;re looking somewhere else. Neo finishes a task you kicked off just before taking lunch. A teammate submits an ESC change request that needs your approval before it can land. Until now, catching any of that meant either keeping the right tab open or hoping the right email reached you.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re introducing the Notification Center: a single inbox in the Pulumi Cloud console for the things that actually need you. It lives behind the bell in the sidebar, with a dot when something&amp;rsquo;s waiting. Notifications arrive in real time — no refresh — and each one carries exactly one action: Review request, View task, Update billing. Click it and you land on the page where you can do the thing, not on a dashboard where you have to go find it.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/notification-center/bell-dropdown.png" alt="Notification bell dropdown"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/notification-center/notification-center.png" alt="Notification center page"&gt;&lt;/p&gt;
&lt;h2 id="what-youll-hear-about"&gt;What you&amp;rsquo;ll hear about&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve started with the moments where being a few minutes late actually costs you something: a Neo task that&amp;rsquo;s paused waiting on your approval, a Neo task that&amp;rsquo;s finished, an ESC change request waiting on your sign-off, and billing conditions like a locked organization or a trial that&amp;rsquo;s about to end. Relevant people in your organization will be notified when there&amp;rsquo;s a pending approval, or billing alert. Nobody gets paged for someone else&amp;rsquo;s work.&lt;/p&gt;
&lt;h2 id="where-youll-hear-about-it"&gt;Where you&amp;rsquo;ll hear about it&lt;/h2&gt;
&lt;p&gt;Every notification type can be delivered two ways — in the console and over email — and you choose per type, per channel. Organization admins set a sensible baseline for everyone; each person can override it for themselves on their account settings page.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/notification-center/notification-settings.png" alt="Notification settings page"&gt;&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;The Notification Center is available today. We&amp;rsquo;re starting with this set of notifications and expanding from there. If there&amp;rsquo;s an event you&amp;rsquo;d rather hear about from the bell than from a colleague on Slack, we&amp;rsquo;d like to know which one.&lt;/p&gt;
&lt;p&gt;Join our &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt; to connect with the Pulumi team and other users, or open an issue on our &lt;a href="https://github.com/pulumi/pulumi"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;</description><author>Tom King</author><category>pulumi-cloud</category><category>features</category><category>pulumi-neo</category><category>esc</category></item><item><title>Automatic Logging for Faster, Secure Debugging</title><link>https://www.pulumi.com/blog/automatic-logging/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/automatic-logging/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/automatic-logging/index.png" /&gt;
&lt;p&gt;Pulumi v3.254.0 introduces automatic logging: every operation is logged in an encrypted log file that can optionally be shared with the Pulumi team for inspection. No more re-running commands just to get logs to the Pulumi team for debugging; instead you can share existing logs securely.&lt;/p&gt;
&lt;p&gt;You might have been in a situation where pulumi hit an error for an unexpected reason, or did something that was not quite right. Currently the process for trying to resolve that is to try and reproduce the error, ideally now with logging enabled. Sometimes the error doesn&amp;rsquo;t reproduce, or the state pulumi was in at the time of the error doesn&amp;rsquo;t exist anymore. And even if the issue reproduces it&amp;rsquo;s a bit of a hassle to do all this again, just to get logs to Pulumi employees who can do something with them. There&amp;rsquo;s also no great mechanism to send the potentially sensitive log file.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;From pulumi v3.254.0 onward, we automatically produce log files for every operation and store them in &lt;code&gt;$PULUMI_HOME/logs&lt;/code&gt;. These log files are encrypted on disk, using the relevant stack&amp;rsquo;s secret manager, whenever it is available, as they still contain secrets at this point. The final file consists of gzip&amp;rsquo;d chunks that are encrypted using AES256-GCM. Log files are gzip&amp;rsquo;d when no secrets manager is available, as no secrets from property values can be in the log at that point.&lt;/p&gt;
&lt;p&gt;Note that the logs are rotated out after 7 days, or after the log directory has reached 500 MB, removing the oldest logs first. This way logs will never fill up your disk, but will still be available after running pulumi commands. These defaults can be overridden with the &lt;code&gt;PULUMI_LOG_ROTATION_MAX_AGE_DAYS&lt;/code&gt; and &lt;code&gt;PULUMI_LOG_ROTATION_MAX_TOTAL_MB&lt;/code&gt; environment variables.&lt;/p&gt;
&lt;p&gt;Locally these logs can be decrypted using &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_logs_decrypt/"&gt;&lt;code&gt;pulumi logs decrypt&lt;/code&gt;&lt;/a&gt;. For this to work the same stack&amp;rsquo;s secret manager as was used for the command needs to be available.&lt;/p&gt;
&lt;h2 id="sharing-logs"&gt;Sharing logs&lt;/h2&gt;
&lt;p&gt;Previously there was no good way to securely share the logs with us. Users were always forced to find a way to send the logs to us on their own. With the latest pulumi version, we introduce the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_logs_share/"&gt;&lt;code&gt;pulumi logs share&lt;/code&gt;&lt;/a&gt; command. This will automatically create a key, safely stored on the server side, and re-encrypt the log with that key, redacting all the secrets by default.&lt;/p&gt;
&lt;p&gt;This key can then be accessed by Pulumi employees and Pulumi employees only via an internal tool to decrypt the log. Again we encrypt the log using AES256-GCM. Given this encryption the log can be shared over unsafe channels, and still be secure, even if it&amp;rsquo;s posted on a GitHub issue.&lt;/p&gt;
&lt;p&gt;And while we strive to keep the Pulumi experience as issue free as possible, this should drastically simplify the debugging experience when it is still necessary.&lt;/p&gt;</description><author>Thomas Gummerer</author><category>logging</category><category>observability</category><category>features</category></item><item><title>Bring Your Terraform Estate Into the Agentic Era</title><link>https://www.pulumi.com/blog/bring-your-terraform-estate-into-the-agentic-era/</link><pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/bring-your-terraform-estate-into-the-agentic-era/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/bring-your-terraform-estate-into-the-agentic-era/index.png" /&gt;
&lt;p&gt;At Pulumi, we are building the platform for &lt;a href="https://www.pulumi.com/what-is/what-is-agentic-infrastructure/"&gt;agentic infrastructure&lt;/a&gt;. Pulumi Cloud provides the guardrails and enterprise readiness needed to safely move fast in this new era. While we are seeing extraordinary adoption — over 40% of our users now manage infrastructure using AI agents — we know many organizations are at different phases in their AI journey and have to balance building for the future with maintaining their existing infrastructure as code (IaC) solutions like Terraform.&lt;/p&gt;
&lt;p&gt;Today, &lt;a href="https://www.pulumi.com/releases/terraform-state-backend-modules-hcl/"&gt;we are launching&lt;/a&gt; three ways that Pulumi lets you avoid trading off building for the future against building for today. You don&amp;rsquo;t have to rip out Terraform to enter the agentic era. Pulumi Cloud brings agentic infrastructure to the IaC estate you already have.&lt;/p&gt;
&lt;h2 id="what-were-shipping-today"&gt;What we&amp;rsquo;re shipping today&lt;/h2&gt;
&lt;p&gt;Last December, our CEO &lt;a href="https://www.pulumi.com/blog/all-iac-including-terraform-and-hcl/"&gt;Joe Duffy laid out his vision&lt;/a&gt; to make Pulumi the platform for all of your infrastructure as code. The capabilities we are launching today make that promise a reality. Pulumi is now fully interoperable with Terraform and OpenTofu and enables organizations to build upon their existing IaC estate rather than starting from scratch as they work toward the agentic infrastructure future.&lt;/p&gt;
&lt;h3 id="pulumi-cloud-as-a-terraform-backend"&gt;Pulumi Cloud as a Terraform backend&lt;/h3&gt;
&lt;p&gt;We are excited to announce the general availability of &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Pulumi Cloud as the backend to your Terraform state&lt;/a&gt;, enabling organizations to seamlessly lift and shift their existing Terraform estates.&lt;/p&gt;
&lt;p&gt;We recognize there is lots of infrastructure that works as is, and switching over to a new management paradigm may not always be possible. Pulumi Cloud support for the Terraform state backend lets organizations maintain their existing Terraform deployment patterns while also unlocking the power of Pulumi Cloud. The following common patterns for running Terraform are now supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Plans and applies run remotely by default&lt;/strong&gt; for new Terraform stacks, following the behavior of HCP Terraform and Terraform Enterprise. When you run a Terraform operation, it executes on a Pulumi-hosted runner rather than your local machine. You get full visibility into these operations both on your local CLI and in the Pulumi Cloud console.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production deployments may be gated with manual approvals&lt;/strong&gt; before applying a Terraform plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this release, stacks with Terraform state are first-class entities in Pulumi Cloud. They get access to all of the capabilities that organizations need to scale in this new AI-first era.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;Manage access to your Terraform stacks at scale&lt;/a&gt;&lt;/strong&gt; using tag-based access control, team role assignments, and user role assignments.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/ai/neo/code-reviews/"&gt;&lt;strong&gt;Take advantage of Neo code reviews&lt;/strong&gt;&lt;/a&gt;. On every pull request, leverage what Pulumi Cloud knows about your running infrastructure and get clear feedback on whether it&amp;rsquo;s safe to merge changes to your Terraform and OpenTofu projects.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/"&gt;&lt;strong&gt;Run preventive policies&lt;/strong&gt;&lt;/a&gt; after a Terraform plan to block non-compliant resources before deployment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Configure your Terraform deployments with Pulumi ESC&lt;/a&gt;&lt;/strong&gt;, which is natively available to Pulumi Cloud-backed Terraform projects, to securely inject OIDC credentials at apply time and expose outputs to downstream stacks and services.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Learn more in &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Using Pulumi Cloud as a Terraform state backend&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="reuse-your-terraform-modules"&gt;Reuse your Terraform modules&lt;/h3&gt;
&lt;p&gt;Pulumi programs, regardless of language, now support &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-modules/"&gt;importing Terraform modules&lt;/a&gt; natively. Organizations can leverage their existing reusable artifacts as is, without having to make a single change. This enables organizations to focus on new infrastructure projects and lets them build those projects in the language of their choice, regardless of what their existing IaC estate is.&lt;/p&gt;
&lt;p&gt;In addition, Pulumi Cloud&amp;rsquo;s private registry can now host Terraform modules alongside Pulumi packages. This enables you to consolidate all of your IaC building blocks in a single source of truth rather than managing disparate solutions and making sure your teams know where to look. Terraform modules hosted in Pulumi Cloud provide maximum interoperability and can be used in both Pulumi and Terraform programs.&lt;/p&gt;
&lt;p&gt;Learn more in &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-modules/"&gt;Using Terraform modules in Pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="build-in-hcl-natively"&gt;Build in HCL natively&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/hcl/"&gt;HashiCorp Configuration Language (HCL)&lt;/a&gt; is now generally available as a first-class language in Pulumi IaC. Like any other Pulumi language, it has full access to the entirety of the Pulumi ecosystem, including thousands of providers. Thanks to our Terraform bridge, if there&amp;rsquo;s a Terraform provider out there, it just works. Best of all, HCL in Pulumi is 100% &lt;a href="https://github.com/opentofu/opentofu"&gt;OpenTofu&lt;/a&gt; compatible with no syntactical differences.&lt;/p&gt;
&lt;p&gt;We recognize there are many teams out there that prefer to work in HCL over general-purpose languages but want to leverage the modern Pulumi IaC engine, or want to be able to use the reusable components their partner teams rely on — regardless of whether those teams work in Terraform or Pulumi.&lt;/p&gt;
&lt;p&gt;Learn more in the &lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/hcl/"&gt;HCL language reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="you-are-still-covered-until-your-hashicorp-renewal"&gt;You are still covered until your HashiCorp renewal&lt;/h2&gt;
&lt;p&gt;We stand by the promise we made last December, and the last thing we want is for you to pay for two IaC solutions. To set your team up for long-term success and ensure your transition to Pulumi is as smooth as possible, we are continuing to offer three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An escape hatch for your current contract.&lt;/strong&gt; We know paying for two IaC solutions at once is a non-starter, so we&amp;rsquo;re letting you apply credits purchased from HashiCorp toward your Pulumi usage until your next renewal, avoiding double pay.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A free IaC modernization workshop.&lt;/strong&gt; Our professional services cloud architects host a free IaC modernization workshop to review where you&amp;rsquo;re at with your IaC already and share best practices for adopting the Pulumi platform at scale, learned from working with world-class organizations like BMW and Supabase. You will leave this session trained up and equipped to succeed with the next phase of your IaC journey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A return on investment (ROI) calculation.&lt;/strong&gt; We will show you how the move to Pulumi will not only be spend-neutral thanks to the escape hatch, but how much value and savings you should expect to see, given our experience helping innovators like Snowflake accelerate their time to market — going from code to cloud in weeks to hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These ensure there&amp;rsquo;s no financial penalty for switching, a clear ROI, and no learning curve. We have always been proud to work with customers of all sizes in all industries, so these offers are available to you whether you&amp;rsquo;re a Global 2000, a startup, or somewhere in between.&lt;/p&gt;
&lt;h2 id="get-started-today"&gt;Get started today&lt;/h2&gt;
&lt;p&gt;The agentic infrastructure era is already here, and we want you to bring your IaC to it. &lt;a href="https://app.pulumi.com/signup"&gt;Get started with Pulumi free&lt;/a&gt; and provision your first stack in minutes.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;d like to get started with the new Terraform/OpenTofu and HCL capabilities, or take advantage of the financial flexibility options, please &lt;a href="https://www.pulumi.com/contact/?form=sales"&gt;get in touch&lt;/a&gt;.&lt;/p&gt;</description><author>Daniel Perlovsky</author><category>infrastructure-as-code</category><category>terraform</category><category>hcl</category><category>pulumi-cloud</category></item><item><title>Discovered Stacks: One Place for All Your Infrastructure</title><link>https://www.pulumi.com/blog/discovered-stacks/</link><pubDate>Thu, 30 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/discovered-stacks/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/discovered-stacks/index.png" /&gt;
&lt;p&gt;Today we&amp;rsquo;re launching &lt;strong&gt;Discovered Stacks&lt;/strong&gt;: Pulumi Cloud now models your AWS CloudFormation stacks and Azure Resource Manager deployments as stacks, right alongside your Pulumi IaC stacks. And when you&amp;rsquo;re ready to bring them under Pulumi management, migration is built in, with every resource tracked until the code provably matches the cloud.&lt;/p&gt;
&lt;h2 id="why-your-infrastructure-doesnt-live-in-one-tool"&gt;Why: your infrastructure doesn&amp;rsquo;t live in one tool&lt;/h2&gt;
&lt;p&gt;Almost nobody&amp;rsquo;s cloud estate is a single technology. There&amp;rsquo;s the CloudFormation that came with the AWS account, the ARM templates from the Azure team, the Terraform from an acquisition, and the Pulumi you&amp;rsquo;re standardizing on. Each tool has its own console, its own grouping, its own idea of state, and no single place shows you everything you run.&lt;/p&gt;
&lt;p&gt;That fragmentation is also why migrations stall. Moving a stack to Pulumi has never been the hard part; &lt;em&gt;knowing where you stand&lt;/em&gt; is. The tracking lives in a spreadsheet, the spreadsheet goes stale the day it&amp;rsquo;s written, and six months later nobody can say which of the 800 resources made it across and which were quietly forgotten.&lt;/p&gt;
&lt;h2 id="nothing-gets-lost"&gt;Nothing gets lost&lt;/h2&gt;
&lt;p&gt;Discovered Stacks gives you confidence that your migration plan or governance efforts will include all resources. This catches a common failure mode where resources are missed by your existing migration scripts or automations. When &lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Pulumi Insights&lt;/a&gt; scans your accounts, every CloudFormation stack and ARM deployment becomes a discovered stack, and every resource in it appears as a row with an explicit migration status: ready to migrate, requiring review before migration, or already migrated. Every status is computed from live state on both ends — what Pulumi manages and what the source tool reports — so it&amp;rsquo;s never a stale annotation someone forgot to update.&lt;/p&gt;
&lt;p&gt;Each resource shows its &lt;strong&gt;origin type&lt;/strong&gt; (&lt;code&gt;AWS::S3::Bucket&lt;/code&gt;) next to its &lt;strong&gt;Pulumi type&lt;/strong&gt; (&lt;code&gt;aws:s3/bucket:Bucket&lt;/code&gt;), with the origin properties side by side with Pulumi&amp;rsquo;s view, so you can verify that Pulumi sees exactly what your source tool sees before you change anything. Decisions you make along the way (&lt;em&gt;this resource was deleted, that policy is covered by its parent role&lt;/em&gt;) are recorded by marking the resource resolved: it stays visible to your whole team, deliberately handled rather than quietly forgotten. The spreadsheet is retired.&lt;/p&gt;
&lt;p&gt;&lt;img src="resources-list.png" alt="The Resources grid of a discovered CloudFormation stack in Pulumi Cloud: each row pairs the Pulumi type (aws:sns:Topic) with its origin type (AWS::SNS::Topic), a Managed By column reading CloudFormation, and a provider link out to the resource in the AWS console."&gt;&lt;/p&gt;
&lt;h2 id="migration-on-your-terms"&gt;Migration on your terms&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re ready to migrate, the console is where you plan and build confidence. &lt;strong&gt;Migrate with Neo&lt;/strong&gt; hands the job to &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt;, which imports the resources, reconciles the generated program, and opens a pull request for review. If you prefer local development, &lt;strong&gt;Generate Import Commands&lt;/strong&gt; gives you the raw materials, and the same API lets your own agents drive the flow.&lt;/p&gt;
&lt;p&gt;Two things hold regardless of the path. Progress is &lt;em&gt;derived&lt;/em&gt;: a resource shows as migrated when it actually exists in the target Pulumi stack, not when someone checks a box. And the quality gate is a &lt;strong&gt;zero-diff &lt;code&gt;pulumi preview&lt;/code&gt;&lt;/strong&gt; — the migration is done when the code demonstrably matches your cloud.&lt;/p&gt;
&lt;p&gt;Terraform stacks whose state you &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;store in Pulumi Cloud&lt;/a&gt; get the same treatment through a new &lt;strong&gt;Migration&lt;/strong&gt; tab, with statuses derived from the Terraform state.&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;/h2&gt;
&lt;p&gt;Open the &lt;strong&gt;Stacks&lt;/strong&gt; page in &lt;a href="https://app.pulumi.com/"&gt;Pulumi Cloud&lt;/a&gt;, turn on &lt;strong&gt;Show Discovered Stacks&lt;/strong&gt;, and your CloudFormation and ARM estates appear next to your IaC. From there:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read the &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/discovered-stacks/"&gt;Discovered Stacks documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://www.pulumi.com/blog/discovered-stacks-migrate-cloudformation-to-pulumi/"&gt;step-by-step migration tutorial&lt;/a&gt; to take a CloudFormation stack all the way to Pulumi.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&amp;rsquo;d love to hear how it works on your estate — reach out through &lt;a href="https://github.com/pulumi/pulumi-cloud-requests"&gt;Pulumi feedback&lt;/a&gt; or your customer success team.&lt;/p&gt;</description><author>Alejandro Cotroneo</author><category>features</category><category>insights</category><category>pulumi-cloud</category></item><item><title>Enforce Access Token Expiry Policies in Pulumi Cloud</title><link>https://www.pulumi.com/blog/access-token-expiry-policy/</link><pubDate>Mon, 27 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/access-token-expiry-policy/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/access-token-expiry-policy/index.png" /&gt;
&lt;p&gt;Pulumi Cloud organizations can now enforce a maximum expiry on the access tokens used against them. Organization admins can set a cap in days, and from that point on, personal, organization, and team tokens operating on resources in the org must carry an expiration within the cap for requests to succeed. Tokens that never expire, or that have too much lifetime remaining, get rejected with an error that tells the user exactly how to regain access.&lt;/p&gt;
&lt;h2 id="why-cap-token-lifetimes"&gt;Why cap token lifetimes&lt;/h2&gt;
&lt;p&gt;Many organizations already have a credential rotation policy that says tokens must expire, but until now, Pulumi Cloud could only &lt;em&gt;recommend&lt;/em&gt; an expiry at creation time. Nothing stopped a member from creating a never-expiring personal token, and nothing aged out the long-lived tokens created before your policy existed.&lt;/p&gt;
&lt;p&gt;That gap matters because a leaked token is only as dangerous as its remaining lifetime. A token that never expires is a standing liability.&lt;/p&gt;
&lt;p&gt;By adding support for access token expiry policies, Pulumi Cloud now closes the gap at the platform level. Once you&amp;rsquo;ve set the cap, Pulumi Cloud enforces it immediately for your organization, including for tokens that already exist.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;In your organization&amp;rsquo;s settings, navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Other&lt;/strong&gt; and scroll to &lt;strong&gt;Access token expiry policy&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/expiry-policy-card.png" alt="The access token expiry policy card in Pulumi Cloud organization settings, with a 14-day maximum entered and buttons to preview affected tokens and save the policy."&gt;&lt;/p&gt;
&lt;p&gt;You can also get there from the &lt;strong&gt;Access Tokens&lt;/strong&gt; tab, where a banner shows whether a policy is in effect — select &lt;strong&gt;Edit policy&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/expiry-policy-banner.png" alt="The banner on the Access Tokens tab stating that the organization caps access token expiry at 14 days, with an Edit policy link."&gt;&lt;/p&gt;
&lt;p&gt;The policy is a single number: the maximum expiry, in days, for tokens used against your organization. Compliance is checked on every request, and a token complies when both of these are true:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It has an expiration date. Never-expiring tokens violate any policy.&lt;/li&gt;
&lt;li&gt;Its &lt;em&gt;remaining lifetime&lt;/em&gt; — the time between now and its expiration — is within the cap.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because compliance is based on remaining lifetime rather than the expiry chosen at creation, the policy is pragmatic about existing credentials: a token created a year ago with a two-year expiry becomes compliant once it has less than the cap remaining. You&amp;rsquo;re enforcing exposure going forward, not retroactively punishing old tokens that are already near the end of their life.&lt;/p&gt;
&lt;p&gt;Enforcement is tailored to each token type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Organization and team tokens&lt;/strong&gt; can&amp;rsquo;t be created out of compliance: the creation dialog caps the expiry picker at your policy maximum, and the API rejects requests that exceed it. Existing machine tokens that violate the policy stop authenticating and need to be recreated with a compliant expiry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Personal tokens&lt;/strong&gt; span all of a user&amp;rsquo;s organizations, so they can&amp;rsquo;t be blocked at creation. Instead, a non-compliant personal token is rejected when it&amp;rsquo;s used against your organization, and the member sees an error explaining the policy and how to fix it. The personal token creation dialog also warns members when a chosen expiry doesn&amp;rsquo;t meet a policy in one of their organizations, steering them toward a compliant choice up front.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web console sessions are unaffected&lt;/strong&gt;, as are the short-lived tokens issued through &lt;a href="https://www.pulumi.com/docs/administration/guides/oidc-issuers/"&gt;OIDC token exchange&lt;/a&gt; — those are already bounded by their issuer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once a policy is active, the creation dialog does the steering for you — the expiry picker tops out at the policy maximum:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/new-token-dialog-capped.png" alt="The New Access Token dialog with the expiration picker set to &amp;ldquo;14 Days (org policy max)&amp;rdquo; and helper text noting the 14-day policy maximum."&gt;&lt;/p&gt;
&lt;h2 id="rolling-it-out-without-breaking-ci"&gt;Rolling it out without breaking CI&lt;/h2&gt;
&lt;p&gt;The riskiest moment for any new enforcement policy is the moment you turn it on. Two things make that safe here.&lt;/p&gt;
&lt;p&gt;First, &lt;strong&gt;Preview affected tokens&lt;/strong&gt; shows you the blast radius before you save: the organization and team tokens that would stop authenticating under the proposed cap, by name and creator. Recreate those credentials with compliant expiries first, then save the policy.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/preview-affected-tokens.png" alt="The preview listing one machine token that would fail to authenticate under a 14-day policy, with a note that non-compliant personal tokens are rejected at request time."&gt;&lt;/p&gt;
&lt;p&gt;Second, rejections are designed to be self-explanatory. A blocked request fails with a &lt;code&gt;403 Forbidden&lt;/code&gt; that names your organization and its policy maximum, so a member whose personal token no longer complies knows immediately what happened and what to do: generate a new token that meets the policy. Policy changes are also recorded in your organization&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/administration/security-compliance/audit-logs/"&gt;audit logs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/access-token-expiry-policy/policy-rejection-cli.png" alt="A pulumi up run rejected with a 403 error stating that the acme-corp organization enforces a max access token expiry of 14 days that the current token does not meet."&gt;&lt;/p&gt;
&lt;p&gt;A reasonable rollout looks like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Decide on a cap that matches your rotation policy. 90 days is a common choice for CI credentials.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Preview affected tokens&lt;/strong&gt; and recreate any non-compliant machine tokens.&lt;/li&gt;
&lt;li&gt;Socialize the change in your organization: personal tokens without a compliant expiry will stop working against the organization.&lt;/li&gt;
&lt;li&gt;Save the policy. From here on, the platform enforces it for you.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;The access token expiry policy is available now in your organization&amp;rsquo;s access settings. For the full reference — compliance rules, per-token-type behavior, and exemptions — see the &lt;a href="https://www.pulumi.com/docs/administration/concepts/access-tokens/#access-token-expiry-policy"&gt;access tokens documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have feedback, we&amp;rsquo;d love to hear it in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Devon Grove</author><category>features</category><category>security</category></item><item><title>Preview ESC Changes with Environment Overrides</title><link>https://www.pulumi.com/blog/preview-esc-environment-changes-with-draft-references/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/preview-esc-environment-changes-with-draft-references/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/preview-esc-environment-changes-with-draft-references/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; makes it easy to store configuration and secrets for your Pulumi programs, and with &lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals for ESC&lt;/a&gt; you can review and approve changes before they go live. The new &lt;code&gt;--override-env&lt;/code&gt; flag lets you preview any environment change, including an unapproved draft, to see exactly how it would affect your stack before it becomes the latest version.&lt;/p&gt;
&lt;h2 id="example-scenario"&gt;Example scenario&lt;/h2&gt;
&lt;p&gt;Your team stores production app configuration in ESC and has enabled &lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals&lt;/a&gt; to keep bad values out of critical infrastructure. But one important question remains: how can reviewers properly validate a configuration change before approving it?&lt;/p&gt;
&lt;h2 id="introducing-draft-references-and-the-override-env-flag"&gt;Introducing: draft references and the &amp;ndash;override-env flag&lt;/h2&gt;
&lt;p&gt;We are introducing a new &lt;code&gt;--override-env&lt;/code&gt; flag to the Pulumi CLI that works with every Pulumi operation that can consume ESC environments: &lt;code&gt;preview&lt;/code&gt;, &lt;code&gt;up&lt;/code&gt;, &lt;code&gt;refresh&lt;/code&gt;, and &lt;code&gt;destroy&lt;/code&gt;. This makes it easy to test configuration changes on the fly, giving your team the confidence to validate them as part of the review process.&lt;/p&gt;
&lt;h3 id="example-usages"&gt;Example usages&lt;/h3&gt;
&lt;p&gt;The basic usage is &lt;code&gt;--override-env &amp;lt;env&amp;gt;=&amp;lt;replacement&amp;gt;&lt;/code&gt;, and you can override multiple environments at once!
In this example, we are running a &lt;code&gt;pulumi preview&lt;/code&gt; with environments &lt;code&gt;app/myenv&lt;/code&gt; and &lt;code&gt;app/myenv2&lt;/code&gt; replaced by their draft versions (denoted by &lt;code&gt;@draft:&amp;lt;draft-id&amp;gt;&lt;/code&gt;).&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pulumi preview \
--override-env &amp;#34;app/myenv=app/myenv@draft:123e4567-e89b-12d3-a456-426614174000&amp;#34; \
--override-env &amp;#34;app/myenv2=app/myenv2@draft:123e4567-e89b-12d3-a456-426614174000&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;--override-env&lt;/code&gt; flag not only works with draft references, but for any environment too! Here is an example of deploying your stack with your AWS test environment:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pulumi up --override-env &amp;#34;aws-login/prod=aws-login/testing&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: &lt;code&gt;--override-env&lt;/code&gt; can also override environments that are imported (directly or indirectly) from the ESC environment in your stack config. This allows you to override any environment in the import chain for full flexibility.&lt;/p&gt;
&lt;h2 id="ways-to-use-it"&gt;Ways to use it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Validate a draft ESC environment with your stack before approving&lt;/li&gt;
&lt;li&gt;One-off debugging without editing stack config&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Draft references and &lt;code&gt;--override-env&lt;/code&gt; are available today in the Pulumi CLI. Upgrade to the &lt;a href="https://www.pulumi.com/docs/install/"&gt;latest release&lt;/a&gt; and try it out! To learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/concepts/approvals/"&gt;Approvals for ESC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/get-started/"&gt;Get started with Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Sean Yeh</author><category>esc</category><category>features</category><category>configuration-management</category></item><item><title>The Standalone ESC CLI Retired: Use pulumi env</title><link>https://www.pulumi.com/blog/esc-cli-retiring-use-pulumi-env/</link><pubDate>Wed, 22 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/esc-cli-retiring-use-pulumi-env/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-cli-retiring-use-pulumi-env/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; CLI v0.26.0 is the latest standalone release. We encourage users to use the &lt;a href="https://www.pulumi.com/docs/iac/cli/"&gt;Pulumi CLI&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/pulumi/esc"&gt;ESC repository&lt;/a&gt; has been archived and the code now lives under &lt;a href="https://github.com/pulumi/pulumi"&gt;pulumi&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-are-we-making-this-change"&gt;Why are we making this change&lt;/h2&gt;
&lt;p&gt;Pulumi ESC is the best way to store and manage configuration and secrets in your Pulumi programs and while you can certainly use ESC to store secrets and configurations for your applications or to manage your AI agents&amp;rsquo; credentials, it&amp;rsquo;s still a core feature of &lt;a href="https://www.pulumi.com/docs/iac/guides/basics/pulumi-cloud-vs-oss/"&gt;Pulumi Cloud&lt;/a&gt;, and we want to make sure we deliver a consistent experience across our entire suite.&lt;/p&gt;
&lt;p&gt;In addition to consistency, ESC and the Pulumi CLI share a lot of capabilities to interface to Pulumi Cloud and we want to make it easier and simpler for our customers: it&amp;rsquo;s now easier to understand which Pulumi organization you are working with, which user is logged in, etc.&lt;/p&gt;
&lt;h3 id="playing-nicer-with-humans-and-ai-agents"&gt;Playing nicer with humans and AI agents&lt;/h3&gt;
&lt;p&gt;A single CLI means one binary to install, one login to manage, and one place to look things up. This simplicity is beneficial whether the operator is a person or an agent.&lt;/p&gt;
&lt;p&gt;AI agents love code, and they love CLIs. By unifying the Pulumi CLI and ESC we offer a single place to look up operations around your Pulumi programs. Agents can now reason better about where to store configuration and secrets, without being confused by multiple CLI options that interface against the same service.&lt;/p&gt;
&lt;h3 id="faster-improvements"&gt;Faster improvements&lt;/h3&gt;
&lt;p&gt;With a shared CLI, any improvement to account management is automatically delivered to both: Pulumi and ESC users. At the same time, both benefit from ESC improvements and new features from day 1.&lt;/p&gt;
&lt;p&gt;ESC is a core component of our platform; a separate interface no longer makes sense.&lt;/p&gt;
&lt;h3 id="the-same-code-all-along"&gt;The same code all along&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re wondering what actually changes under the hood: nothing about how the commands work. The &lt;code&gt;pulumi env&lt;/code&gt; commands were never a reimplementation — the Pulumi CLI has built them from the ESC CLI&amp;rsquo;s own code since ESC&amp;rsquo;s first release, which is why the same command surface has always been available under &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_env/"&gt;&lt;code&gt;pulumi env&lt;/code&gt;&lt;/a&gt;. What we&amp;rsquo;re retiring is a second way to ship and install that code, not the code itself.&lt;/p&gt;
&lt;h2 id="do-i-need-to-update"&gt;Do I need to update?&lt;/h2&gt;
&lt;p&gt;If you are using the ESC CLI, you should switch as soon as possible, as the standalone binary will not get the latest features. Don&amp;rsquo;t worry — the mapping is mechanical, and the &lt;a href="https://www.pulumi.com/docs/esc/guides/migrate-from-esc-cli/"&gt;migration guide&lt;/a&gt; covers it command by command:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;esc env &amp;lt;command&amp;gt;&lt;/code&gt; becomes &lt;code&gt;pulumi env &amp;lt;command&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;esc env ls&lt;/code&gt; becomes &lt;code&gt;pulumi env ls&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;esc open&lt;/code&gt; and &lt;code&gt;esc run&lt;/code&gt; shortcuts become &lt;code&gt;pulumi env open&lt;/code&gt; and &lt;code&gt;pulumi env run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;esc login&lt;/code&gt;, &lt;code&gt;esc logout&lt;/code&gt;, and &lt;code&gt;esc version&lt;/code&gt; become &lt;code&gt;pulumi login&lt;/code&gt;, &lt;code&gt;pulumi logout&lt;/code&gt;, and &lt;code&gt;pulumi version&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are already using the Pulumi CLI, you have nothing to worry about; this has no effect since ESC commands were already available under the &lt;code&gt;pulumi env&lt;/code&gt; sub-command.&lt;/p&gt;
&lt;p&gt;Ready to switch? &lt;a href="https://www.pulumi.com/docs/install/"&gt;Install the Pulumi CLI&lt;/a&gt; if you don&amp;rsquo;t have it yet, then run &lt;code&gt;pulumi env ls&lt;/code&gt; to see your environments. Every command is documented in the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_env/"&gt;&lt;code&gt;pulumi env&lt;/code&gt; reference&lt;/a&gt;.&lt;/p&gt;</description><author>Pablo Terradillos</author><author>Boris Schlosser</author><category>esc</category><category>features</category></item><item><title>Connect Your Cloud Accounts to Pulumi in Minutes</title><link>https://www.pulumi.com/blog/connect-your-cloud-accounts-to-pulumi-in-minutes/</link><pubDate>Wed, 15 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/connect-your-cloud-accounts-to-pulumi-in-minutes/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/connect-your-cloud-accounts-to-pulumi-in-minutes/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Pulumi Insights&lt;/a&gt; gives you visibility and governance across your entire cloud footprint, but that visibility is only as complete as the set of accounts you&amp;rsquo;ve connected. Until now, connecting an account meant repeating a manual setup for each one: OIDC configuration, hand-written &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environments, and per-account scan and policy setup. For an organization with dozens or hundreds of AWS accounts, Azure subscriptions, or Google Cloud projects, that per-account friction was the biggest obstacle to getting a complete picture. Today, the new &lt;strong&gt;Connect cloud accounts&lt;/strong&gt; wizard removes it: discover every account in your cloud organization, select the ones you want, and onboard them all in a single guided flow.&lt;/p&gt;
&lt;h2 id="from-hours-of-setup-to-a-single-flow"&gt;From hours of setup to a single flow&lt;/h2&gt;
&lt;p&gt;The time savings are real: connecting a batch of accounts across AWS, Azure, and Google Cloud takes about three minutes end to end. Setting up those same accounts with the manual per-account workflow would take hours to days.&lt;/p&gt;
&lt;p&gt;The wizard handles the entire onboarding lifecycle for AWS, Microsoft Azure, and Google Cloud:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bulk discovery&lt;/strong&gt;: Authenticate once with your cloud organization and the wizard lists every account, subscription, or project you can access. Accounts that are already connected are recognized and skipped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic OIDC setup&lt;/strong&gt;: The recommended flows configure each account with short-lived credentials based on OpenID Connect (OIDC) and workload identity federation. No long-lived cloud secrets are stored in Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESC environments, created for you&lt;/strong&gt;: The wizard generates &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environments that follow the best practices from the manual OIDC guides — environments that previously had to be authored one by one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scans and policies from day one&lt;/strong&gt;: By default, scheduled discovery scans and a &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/pre-built-packs/"&gt;pre-built policy pack&lt;/a&gt; are applied to every account as part of setup: the Pulumi Best Practices pack on the Team and Enterprise editions, or a compliance pack (CIS, or NIST 800-53 for AWS and Google Cloud) on Business Critical.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;The wizard walks you through five steps: choose a provider, authenticate, select accounts, configure discovery and policy, and review the results. You can open it from &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Accounts&lt;/strong&gt; in the Pulumi Cloud console, or from the &lt;strong&gt;Get to know Pulumi&lt;/strong&gt; card on the home dashboard.&lt;/p&gt;
&lt;p&gt;Authentication uses each provider&amp;rsquo;s native federation mechanism: IAM Identity Center (SSO) for AWS, Microsoft Entra ID workload identity federation for Azure, and Workload Identity Federation for Google Cloud. After you sign in, the wizard discovers the accounts in your organization and pre-selects everything that isn&amp;rsquo;t already connected. You can search, select all, or toggle individual accounts.&lt;/p&gt;
&lt;p&gt;&lt;img src="account-picker.png" alt="The account picker showing discovered AWS accounts with checkboxes, a search box, and a select all option"&gt;&lt;/p&gt;
&lt;h3 id="choose-the-right-access-level-for-your-security-posture"&gt;Choose the right access level for your security posture&lt;/h3&gt;
&lt;p&gt;Not every team wants to grant write access on day one. The wizard offers two access levels, and you can set them per account:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Build &amp;amp; Manage (read and write)&lt;/strong&gt;: Enables the full platform: &lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt;, infrastructure as code, deployments, and policies that remediate issues automatically (Business Critical).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discovery &amp;amp; Policy (read-only)&lt;/strong&gt;: Limited to discovery scanning and inventory. Pulumi can&amp;rsquo;t modify your infrastructure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your security review requires it, start everything read-only and raise access for specific accounts later.&lt;/p&gt;
&lt;p&gt;&lt;img src="access-level.png" alt="The accounts step showing the selected accounts summary, the Build and Manage access level card, and per account access controls"&gt;&lt;/p&gt;
&lt;h3 id="everything-set-up-nothing-hidden"&gt;Everything set up, nothing hidden&lt;/h3&gt;
&lt;p&gt;When setup completes, the summary shows exactly what was created: the ESC environments grouped by access level, the state of discovery scanning, and the policy pack applied. If any account fails to connect, the summary lists it with the specific error so you can fix the cause and re-run the wizard. Accounts that connected successfully are skipped on retry.&lt;/p&gt;
&lt;p&gt;&lt;img src="summary.png" alt="The summary step showing setup complete with discovery running, the policy pack applied, and the list of created ESC environments"&gt;&lt;/p&gt;
&lt;p&gt;For security reviewers, the docs include a full accounting of &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/connect-cloud-accounts/#what-the-wizard-creates"&gt;what the wizard creates&lt;/a&gt; in your cloud provider and in Pulumi Cloud: the IAM roles, app registrations, and service accounts on the cloud side, and the ESC environments and Insights accounts on the Pulumi side.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;The Connect cloud accounts wizard is available now for all Pulumi Cloud organizations. To connect your first accounts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href="https://app.pulumi.com/"&gt;&lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Accounts&lt;/strong&gt;&lt;/a&gt; in the Pulumi Cloud console and select &lt;strong&gt;Connect cloud accounts&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Follow the guided flow for AWS, Azure, or Google Cloud.&lt;/li&gt;
&lt;li&gt;Explore your &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/search/"&gt;discovered resources&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-findings/"&gt;policy findings&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/connect-cloud-accounts/"&gt;Connect cloud accounts documentation&lt;/a&gt; — prerequisites, each wizard step in detail, and troubleshooting&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Insights &amp;amp; Governance overview&lt;/a&gt; — full documentation for discovery and policy capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; — how the generated environments manage cloud credentials with OIDC&lt;/li&gt;
&lt;/ul&gt;</description><author>Levi Blackstone</author><category>insights</category><category>esc</category><category>pulumi-cloud</category></item><item><title>Introducing Usage Limits for Pulumi Neo</title><link>https://www.pulumi.com/blog/neo-usage-limits/</link><pubDate>Tue, 14 Jul 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-usage-limits/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-usage-limits/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt; is an AI agent that takes on real infrastructure work, and it&amp;rsquo;s natural to want to hand it more and more. Usage limits give you control so you can do exactly that: set a monthly dollar limit, and Neo pauses when your organization reaches it.&lt;/p&gt;
&lt;h2 id="how-usage-limits-work"&gt;How usage limits work&lt;/h2&gt;
&lt;p&gt;Your organization limit is a single monthly dollar amount covering all Neo usage across the org. To set one:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the Pulumi Cloud console, navigate to &lt;strong&gt;Settings → Billing &amp;amp; usage → Neo token usage&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Manage token usage&lt;/strong&gt; panel, enter an organization limit.&lt;/li&gt;
&lt;li&gt;Save your changes.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When usage reaches the limit, Neo pauses for the rest of the billing period and resumes automatically at the start of the next one. An Admin or Billing Manager can raise the limit to resume before then.&lt;/p&gt;
&lt;p&gt;&lt;img src="manage-token-usage.png" alt="The Manage token usage panel, where an admin sets the organization&amp;rsquo;s monthly Neo limit and turns on email notifications."&gt;&lt;/p&gt;
&lt;p&gt;Enforcement happens at a natural boundary in Neo&amp;rsquo;s work, so a task already in progress finishes its current step before pausing. As a result, usage can go a few dollars over the set limit.&lt;/p&gt;
&lt;h2 id="per-member-limits-and-alerts"&gt;Per-member limits and alerts&lt;/h2&gt;
&lt;p&gt;You can also set a separate limit for each member. A member is paused at whichever limit is smaller: their own or the organization&amp;rsquo;s. For example, a member with a $200 limit under a $150 organization limit pauses at $150, because the organization limit is smaller.&lt;/p&gt;
&lt;p&gt;&lt;img src="per-member-limits.png" alt="The per-member limits table, showing each member&amp;rsquo;s amount used and effective limit for the billing period."&gt;&lt;/p&gt;
&lt;p&gt;Turn on &lt;strong&gt;Enable email notifications&lt;/strong&gt; to get a heads-up before you reach the limit. Billing admins are alerted at 50%, 80%, and 95% of the organization limit, with a final notice at 100% when Neo pauses.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Set your usage limits and stay in control as your organization hands Neo more and more work. Usage limits are available today for organizations on a paid plan, and an &lt;strong&gt;Admin&lt;/strong&gt; or &lt;strong&gt;Billing Manager&lt;/strong&gt; can set them.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.pulumi.com/signin"&gt;Sign in to Pulumi Cloud&lt;/a&gt; and set your first organization limit&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/ai/neo/usage-limits/"&gt;Read the Neo usage limits documentation&lt;/a&gt; for per-member limits, alerts, and enforcement details&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.pulumi.com/"&gt;Join the Community Slack&lt;/a&gt; to share your feedback&lt;/li&gt;
&lt;/ul&gt;</description><author>John Keiser</author><category>pulumi-neo</category><category>ai</category><category>ai-agents</category><category>features</category></item><item><title>Sign in to Pulumi Cloud with Passkeys</title><link>https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/</link><pubDate>Mon, 13 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/meta.png" /&gt;
&lt;p&gt;Pulumi Cloud now supports passkeys for users who sign in with email and password. Select a button, approve with Touch ID, Face ID, Windows Hello, or your hardware key, and you&amp;rsquo;re signed in.&lt;/p&gt;
&lt;p&gt;A passkey is a public-key credential stored on your device: your phone, your laptop, a hardware key (YubiKey, Google Titan, etc.), or your password manager can all function as the authenticator. When you sign in, your device authenticates you locally and signs a challenge from Pulumi Cloud with the private key.&lt;/p&gt;
&lt;p&gt;The private key stays on your device — Pulumi Cloud never sees or stores it. Passkeys are built on the &lt;a href="https://www.w3.org/TR/webauthn-3/"&gt;WebAuthn&lt;/a&gt; standard, so they&amp;rsquo;re already supported on every major browser and operating system.&lt;/p&gt;
&lt;h2 id="who-this-is-for"&gt;Who this is for&lt;/h2&gt;
&lt;p&gt;This release applies to users who sign in to Pulumi Cloud with an email address and password. If you sign in through an identity provider (IdP), such as GitHub OAuth, GitLab, Bitbucket, Google, or your organization&amp;rsquo;s SAML SSO, your existing flow is unchanged.&lt;/p&gt;
&lt;h2 id="why-passkeys"&gt;Why passkeys&lt;/h2&gt;
&lt;p&gt;Passwords have always been the weakest link in account security. Since they are shared secrets, they are vulnerable to phishing attacks, and every place you type one is a place that can be impersonated or a data store that can be leaked. Passkeys swap that out for a per-site key pair that lives on your device:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phishing-resistant by design.&lt;/strong&gt; A passkey is bound to the exact origin it was registered for. A look-alike domain can&amp;rsquo;t trigger your authenticator.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synced across your devices.&lt;/strong&gt; Apple iCloud Keychain, Google Password Manager, 1Password, Dashlane, Bitwarden: most credential managers now sync passkeys end-to-end-encrypted to every device you&amp;rsquo;ve signed in on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discoverable.&lt;/strong&gt; Pulumi Cloud doesn&amp;rsquo;t need to know which user you are before you authenticate. Just select &amp;ldquo;Sign in with a passkey&amp;rdquo; and your device offers the right credential.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing to remember.&lt;/strong&gt; A passkey lives on your device. There&amp;rsquo;s no string to memorize, and no sensitive credential stored by us.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setting-up-a-passkey"&gt;Setting up a passkey&lt;/h2&gt;
&lt;p&gt;The next time you sign in with a password, Pulumi Cloud will ask if you&amp;rsquo;d like to configure a passkey. It&amp;rsquo;s a single-step prompt, so you can enroll once and take advantage of passkeys on every subsequent sign-in.&lt;/p&gt;
&lt;p&gt;If you dismiss the prompt and would like to add one later, or want to add multiple passkeys, navigate to &lt;strong&gt;Account Settings → Passkeys&lt;/strong&gt; under your user profile. Select &lt;strong&gt;Register a passkey&lt;/strong&gt;, complete the OS-level prompt (Touch ID, Face ID, Windows Hello, or your hardware key), and you&amp;rsquo;re done. Pulumi Cloud will pick a sensible default name like &lt;code&gt;&amp;quot;iCloud Keychain&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;Chrome on macOS&amp;quot;&lt;/code&gt; based on the authenticator, but you can rename it inline anytime under &lt;strong&gt;Account Settings → Passkeys&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/passkey-support-in-pulumi-cloud/account-settings-passkeys.png" alt="Pulumi Cloud Account Settings page showing the Passkeys section, with a &amp;ldquo;Register a passkey&amp;rdquo; button and an enrolled passkey named &amp;ldquo;Pulumipus&amp;rsquo;s iPhone&amp;rdquo;."&gt;&lt;/p&gt;
&lt;p&gt;You can register as many passkeys as you want. Typical setups are one per personal device, or one synced credential plus a hardware key as backup. Removing a passkey takes effect immediately; deleted credentials cannot be used to sign in.&lt;/p&gt;
&lt;h2 id="signing-in"&gt;Signing in&lt;/h2&gt;
&lt;p&gt;Depending on how you arrive:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explicit sign-in.&lt;/strong&gt; On the sign-in page, select &lt;strong&gt;Sign in with a passkey&lt;/strong&gt;. Your browser opens the passkey picker, and you authenticate from there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autofill.&lt;/strong&gt; If your browser supports &lt;a href="https://web.dev/articles/passkey-form-autofill"&gt;conditional mediation&lt;/a&gt; (Chrome, Safari, Edge, recent Firefox), the email field on the sign-in page proactively offers your registered passkeys as autofill suggestions. Pick one and you&amp;rsquo;re signed in.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-about-my-existing-password-and-mfa"&gt;What about my existing password and MFA?&lt;/h2&gt;
&lt;p&gt;Your existing password still works. Passkeys are an additional sign-in option, not a replacement, and they don&amp;rsquo;t disable password sign-in on your account. If you lose access to every registered passkey, you can still sign in with your email and password as you always have, then register a new passkey from settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Other 2FA still applies.&lt;/strong&gt; If you have TOTP-based MFA enabled on your Pulumi account, a passkey sign-in will still prompt for your second factor. WebAuthn doesn&amp;rsquo;t reliably tell us &lt;em&gt;how&lt;/em&gt; you unlocked the passkey on your device (biometric, PIN, or something weaker), so we can&amp;rsquo;t safely treat the passkey itself as proof of two factors. Your existing MFA configuration remains the boundary it always was.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Passkey support is generally available today for every Pulumi Cloud user who signs in with email and password, at no additional cost and with no configuration. Visit &lt;a href="https://app.pulumi.com/account/profile"&gt;your account settings&lt;/a&gt; to register your first passkey, and let us know what you think on &lt;a href="https://slack.pulumi.com/"&gt;our community Slack&lt;/a&gt; or &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Devon Grove</author><category>features</category><category>security</category><category>product-launches</category></item><item><title>New: Versioned CLI and SDK Docs</title><link>https://www.pulumi.com/blog/previous-cli-and-sdk-version-docs/</link><pubDate>Tue, 07 Jul 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/previous-cli-and-sdk-version-docs/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/previous-cli-and-sdk-version-docs/index.png" /&gt;
&lt;p&gt;Pinned to an older Pulumi CLI or SDK version and finding that the docs describe a newer release? The &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;Pulumi CLI command reference&lt;/a&gt; and the SDK API docs now include a version selector, so the documentation you&amp;rsquo;re reading matches the version you&amp;rsquo;re actually running.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you open the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;CLI command reference&lt;/a&gt;, you&amp;rsquo;ll see a version dropdown near the top of the page, below the title. The SDK API docs carry the same dropdown in the upper-right corner. Choose a release, and the page loads the documentation generated for that exact version.&lt;/p&gt;
&lt;p&gt;&lt;img src="cli-version-selector.png" alt="Version selector near the top of the Pulumi CLI command reference"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="sdk-version-selector.png" alt="Version selector in the upper-right corner of the Pulumi Node.js SDK API docs"&gt;&lt;/p&gt;
&lt;h2 id="whats-available"&gt;What&amp;rsquo;s available&lt;/h2&gt;
&lt;p&gt;Alongside the latest release, we keep immutable snapshots of previous versions going back to v3.150.0 (early 2025). The CLI command reference and the Node.js, Python, .NET, and Java SDK API docs are all covered, so the docs you need are only a dropdown away. (The Go SDK is versioned on &lt;a href="https://pkg.go.dev/github.com/pulumi/pulumi/sdk/v3"&gt;pkg.go.dev&lt;/a&gt;, so its documentation lives there rather than in the Pulumi docs.)&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Head to the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/"&gt;CLI command reference&lt;/a&gt; or the &lt;a href="https://www.pulumi.com/docs/reference/"&gt;SDK API docs&lt;/a&gt; and try the version dropdown. Selections are sticky, so when you navigate into a version, you&amp;rsquo;ll be able to click around within that same version without having to choose it again.&lt;/p&gt;
&lt;p&gt;Have feedback? Let us know in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or by opening an issue on &lt;a href="https://github.com/pulumi/docs"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/iac/cli/commands/"
class="btn btn-primary"
&gt;
Browse the CLI command reference
&lt;/a&gt;</description><author>Cam Soper</author><category>pulumi-cli</category><category>features</category><category>announcements</category></item><item><title>Enforce ISO 27001 Across Your AWS Infrastructure</title><link>https://www.pulumi.com/blog/iso-27001-policy-pack-for-aws/</link><pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/iso-27001-policy-pack-for-aws/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/iso-27001-policy-pack-for-aws/index.png" /&gt;
&lt;p&gt;ISO/IEC 27001 is the international standard for information security management. Proving you meet it usually means months of mapping abstract security controls to concrete cloud configuration, then authoring custom checks one resource at a time. We&amp;rsquo;re changing that.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re shipping a pre-built ISO/IEC 27001:2022 policy pack for AWS, live now in Pulumi Cloud as &lt;code&gt;iso-27001-aws&lt;/code&gt;. It encodes the standard&amp;rsquo;s security expectations as 238 ready-to-run policies, so you can align your AWS estate to ISO 27001 in minutes, not months.&lt;/p&gt;
&lt;h2 id="why-iso-27001-matters"&gt;Why ISO 27001 matters&lt;/h2&gt;
&lt;p&gt;For many companies, ISO 27001 is what stands between them and a customer or a market. The sooner you can reach a certifiable state and prove you stay there, the less compliance slows the business down. The pack collapses months of policy work into something you run continuously, so security keeps pace with growth instead of blocking it.&lt;/p&gt;
&lt;h2 id="how-the-pack-maps-to-iso-27001"&gt;How the pack maps to ISO 27001&lt;/h2&gt;
&lt;p&gt;The hard part of ISO 27001 has always been translation: its controls are written in the language of governance and risk management, not in the language of AWS resources. Every team has had to interpret each control and decide what it means for an S3 bucket or an RDS instance.&lt;/p&gt;
&lt;p&gt;The pack does that interpretation for you. Its 238 policies are aligned to the relevant ISO 27001 controls, so each result connects back to the standard instead of leaving you to map it yourself. You can browse the full pack in the &lt;a href="https://www.pulumi.com/docs/reference/pre-built-policy-packs/iso-27001/aws/"&gt;pack reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="audit-and-prevent"&gt;Audit and prevent&lt;/h2&gt;
&lt;p&gt;The same pack works two ways, so you can both reach compliance and stay there:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Audit.&lt;/strong&gt; Scan your existing AWS estate against the pack, including resources that Pulumi doesn&amp;rsquo;t manage. You get an honest baseline of where you stand against ISO 27001 today, with every finding tied back to the control it affects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prevent.&lt;/strong&gt; Run the same pack as a preventative policy during &lt;code&gt;pulumi up&lt;/code&gt; to block non-compliant resources before they&amp;rsquo;re ever created. New infrastructure is born aligned to the standard.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Audit gets you clean. Preventative policies keep you clean.&lt;/p&gt;
&lt;h2 id="a-growing-library-of-pre-built-packs"&gt;A growing library of pre-built packs&lt;/h2&gt;
&lt;p&gt;ISO 27001 joins a growing library of pre-built packs for AWS, each authored and maintained by Pulumi and kept current with its source standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISO/IEC 27001:2022&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CIS Controls v8.1&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NIST SP 800-53 Rev. 5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCI DSS v4.0&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HITRUST CSF v11.5&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pulumi Best Practices&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Adopting any pack means you skip the authoring work entirely, inherit framework mappings maintained by Pulumi, and apply a consistent baseline across every stack and account.&lt;/p&gt;
&lt;h2 id="get-started-today"&gt;Get started today&lt;/h2&gt;
&lt;p&gt;The ISO 27001 pack is available now on the &lt;a href="https://www.pulumi.com/pricing/#pre-built-policy-packs"&gt;Business Critical edition&lt;/a&gt; of Pulumi Cloud:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Browse the &lt;a href="https://www.pulumi.com/docs/reference/pre-built-policy-packs/iso-27001/aws/"&gt;pack reference&lt;/a&gt; to see all 238 policies and how they map to the standard&amp;rsquo;s controls.&lt;/li&gt;
&lt;li&gt;Explore the full &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/pre-built-packs/"&gt;pre-built packs index&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Follow the &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/get-started/"&gt;get-started guide&lt;/a&gt; to run your first audit.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="try-pulumi-policies"&gt;Try Pulumi policies&lt;/h2&gt;
&lt;p&gt;Ready to align your AWS infrastructure to ISO 27001? &lt;a href="https://app.pulumi.com/signup"&gt;Sign up for Pulumi Cloud&lt;/a&gt; and run the pack against your estate, or read the &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/get-started/"&gt;policy get-started guide&lt;/a&gt; to dig in.&lt;/p&gt;
&lt;p&gt;Need a compliance pack for a framework that isn&amp;rsquo;t listed here? Open a request in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests"&gt;pulumi/pulumi-cloud-requests&lt;/a&gt; or come tell us in the &lt;a href="https://slack.pulumi.com/"&gt;community Slack&lt;/a&gt;. We&amp;rsquo;re listening.&lt;/p&gt;</description><author>Dan Biwer</author><category>pulumi-cloud</category><category>policy-as-code</category><category>features</category><category>compliance</category><category>governance</category><category>security</category></item><item><title>Introducing ESC Secret Rotation Webhooks</title><link>https://www.pulumi.com/blog/introducing-esc-secret-rotation-webhooks/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/introducing-esc-secret-rotation-webhooks/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/introducing-esc-secret-rotation-webhooks/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; centralizes your secrets and configuration, and it can &lt;a href="https://www.pulumi.com/docs/esc/concepts/rotators/"&gt;automatically rotate secrets&lt;/a&gt; on a schedule so credentials never go stale. But a rotation is only useful if the systems that depend on it know it happened. ESC secret rotation webhooks close that gap by notifying you the moment a secret rotates.&lt;/p&gt;
&lt;h2 id="introducing-secret-rotation-webhooks"&gt;Introducing secret rotation webhooks&lt;/h2&gt;
&lt;p&gt;With &lt;a href="https://www.pulumi.com/docs/esc/concepts/webhooks/"&gt;ESC webhooks&lt;/a&gt;, you can react to rotations automatically. When ESC rotates an environment&amp;rsquo;s secrets, a webhook can be configured to trigger on either success or failure. Use it to notify your team in Slack, refresh services that hold the old credential, or catch a failed rotation before it causes an outage.&lt;/p&gt;
&lt;h2 id="how-to-configure"&gt;How to configure&lt;/h2&gt;
&lt;h3 id="pulumi-cloud-console"&gt;Pulumi Cloud Console&lt;/h3&gt;
&lt;p&gt;Using the Pulumi Cloud Console, you can now configure webhooks for &amp;ldquo;Environment rotation succeeded&amp;rdquo; and &amp;ldquo;Environment rotation failed&amp;rdquo; in your ESC Environment&amp;rsquo;s Settings page (under &lt;strong&gt;Settings&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Notifications&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;&lt;img src="./rotation-webhook-triggers.png" alt="ESC webhook trigger settings with &amp;ldquo;Environment rotation succeeded&amp;rdquo; and &amp;ldquo;Environment rotation failed&amp;rdquo; selected"&gt;&lt;/p&gt;
&lt;h3 id="pulumi-service-provider"&gt;Pulumi Service Provider&lt;/h3&gt;
&lt;p&gt;You can use the Pulumi Service Provider in your Pulumi program to configure webhooks. Here is an example in TypeScript:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;environmentWebhook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Webhook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;env-webhook&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;active&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;displayName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;env-webhook&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;organizationName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;my-org&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;projectName&lt;/span&gt;: &lt;span class="kt"&gt;environment.project&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;environmentName&lt;/span&gt;: &lt;span class="kt"&gt;environment.name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;payloadUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;filters&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;WebhookFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnvironmentRotationSucceeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WebhookFilters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnvironmentRotationFailed&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="pulumi-cli"&gt;Pulumi CLI&lt;/h3&gt;
&lt;p&gt;You can also use the Pulumi CLI to configure the webhook:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;pulumi env webhook new my-org/project/env env-webhook \
--url https://example.com \
--event environment_rotation_succeeded \
--event environment_rotation_failed
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Secret rotation webhooks are available now for all Pulumi ESC environments. See the &lt;a href="https://www.pulumi.com/docs/esc/concepts/webhooks/"&gt;webhooks documentation&lt;/a&gt; to get started, and share your feedback on our &lt;a href="https://github.com/pulumi/esc"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;</description><author>Sean Yeh</author><category>esc</category><category>rotation</category><category>secrets</category></item><item><title>Neo code reviews: AI code review built for infrastructure</title><link>https://www.pulumi.com/blog/neo-code-reviews/</link><pubDate>Mon, 22 Jun 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-code-reviews/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-code-reviews/index.png" /&gt;
&lt;p&gt;Today we&amp;rsquo;re introducing &lt;a href="https://www.pulumi.com/docs/ai/neo/code-reviews/"&gt;Pulumi Neo code reviews&lt;/a&gt;, now in public preview. Neo code reviews analyze pull request changes in conjunction with what Pulumi Cloud knows about your running infrastructure, providing both high-level and code-level feedback.&lt;/p&gt;
&lt;p&gt;Normal code review agents can&amp;rsquo;t reliably anticipate the impact an infrastructure-as-code change will have. This is because they don&amp;rsquo;t have access to critical aspects of the IaC workflow: the potential impact the update will have, in this case the &lt;code&gt;pulumi preview&lt;/code&gt; output; and the current state of the cloud infrastructure. Neo not only has access to both of those, but also to the entirety of your other cloud context, such as stack relationships and dependencies.&lt;/p&gt;
&lt;h2 id="running-reviews"&gt;Running reviews&lt;/h2&gt;
&lt;p&gt;Neo can review every pull request automatically, or only when someone mentions &lt;code&gt;@pulumi-neo&lt;/code&gt;. Either way, it skips draft pull requests and those opened by bots by default.&lt;/p&gt;
&lt;p&gt;A review is a comment, so it informs the person approving the merge and sits alongside the required checks and branch protection you already enforce. Neo code reviews run inside the same governance as every other Neo task, with the &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;RBAC&lt;/a&gt;, guardrails, and audit logging your organization has set.&lt;/p&gt;
&lt;p&gt;&lt;img src="neo-code-review.png" alt="Neo code review on a GitHub pull request, showing a risk assessment and the resource changes the update would make"&gt;&lt;/p&gt;
&lt;h2 id="enable-code-reviews"&gt;Enable code reviews&lt;/h2&gt;
&lt;p&gt;Neo code reviews are available on GitHub during public preview. They require Pulumi Neo to be enabled for your organization, the &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;Pulumi GitHub App&lt;/a&gt; installed on the repositories you want reviewed, and a one-time grant from each organization user to access their GitHub account under &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt;. If Neo currently posts preview summaries on your pull requests, code reviews are already enabled, and they take the place of those summaries.&lt;/p&gt;
&lt;p&gt;Neo code reviews are free while in public preview. On July 1, 2026, they&amp;rsquo;ll be generally available, and reviews will begin counting toward your organization&amp;rsquo;s Neo token usage, at the same per-token rate as any other Neo task. The &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; shows that rate and the monthly token allotment included with each plan.&lt;/p&gt;
&lt;h2 id="give-it-a-try"&gt;Give it a try&lt;/h2&gt;
&lt;p&gt;Open a pull request against a stack Pulumi manages and see Neo&amp;rsquo;s review. We want to hear what it catches and what it misses, so hop into the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; and tell us.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Trigger Deployments on Git Tags</title><link>https://www.pulumi.com/blog/trigger-deployments-on-git-tags/</link><pubDate>Fri, 05 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/trigger-deployments-on-git-tags/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/trigger-deployments-on-git-tags/index.png" /&gt;
&lt;p&gt;A git tag is how many teams mark a release as ready. Pulumi Deployments can now act on that signal directly: configure a tag-based trigger, push a version tag like &lt;code&gt;v1.2.0&lt;/code&gt;, and Pulumi automatically runs &lt;code&gt;pulumi up&lt;/code&gt; for your stack. No extra pipeline glue, no manual click — your release tag &lt;em&gt;is&lt;/em&gt; the deployment.&lt;/p&gt;
&lt;h2 id="why-tags"&gt;Why tags?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/deployments/concepts/triggers/#push-to-deploy"&gt;Push to Deploy&lt;/a&gt; has long let you preview changes on a pull request and update a stack when commits merge to a branch. That branch-based model is a great fit for continuous delivery to shared development and QA environments, where every merge should flow straight through.&lt;/p&gt;
&lt;p&gt;But promotion to production is often deliberate, not continuous. You merge throughout the day, then decide — separately — that a particular commit is the release. The conventional way to record that decision is a git tag: &lt;code&gt;v1.2.0&lt;/code&gt;, &lt;code&gt;2026.06.0&lt;/code&gt;, &lt;code&gt;release-2026-06-04&lt;/code&gt;. Tagging is already part of most teams&amp;rsquo; release rituals.&lt;/p&gt;
&lt;p&gt;Tag-based triggers connect that ritual to your infrastructure. Instead of wiring up a separate CI job to call the &lt;a href="https://www.pulumi.com/docs/deployments/concepts/triggers/#rest-api"&gt;Pulumi Deployments REST API&lt;/a&gt; on a tag event, you configure the trigger once in your stack&amp;rsquo;s deployment settings and let Pulumi handle the rest.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Tag triggers are controlled by two settings on your stack&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/deployments/concepts/settings/"&gt;deployment configuration&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Run updates for pushed tags&lt;/strong&gt; — a toggle that enables running &lt;code&gt;pulumi up&lt;/code&gt; when a matching tag is pushed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag filters&lt;/strong&gt; — a list of glob patterns that decide which tag names qualify.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tag filters use the same model as the &lt;a href="https://www.pulumi.com/docs/deployments/concepts/settings/#path-filtering"&gt;path filters&lt;/a&gt; you may already know, except the patterns match against the tag name rather than changed file paths. A few examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;v*&lt;/code&gt; — deploy on any tag beginning with &lt;code&gt;v&lt;/code&gt;, such as &lt;code&gt;v1.0.0&lt;/code&gt; and &lt;code&gt;v2.3.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;v*&lt;/code&gt; plus &lt;code&gt;!*-rc*&lt;/code&gt; — deploy on release tags but skip release candidates like &lt;code&gt;v1.2.0-rc1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2026.*&lt;/code&gt; — deploy on calendar-versioned releases such as &lt;code&gt;2026.06.0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Filters prefixed with &lt;code&gt;!&lt;/code&gt; are exclusions, and an exclusion always wins over an include. With no filters configured and the toggle on, every tag push deploys. Deleting a tag never triggers a deployment.&lt;/p&gt;
&lt;p&gt;When a tag push kicks off a deployment, Pulumi sets the &lt;code&gt;PULUMI_CI_TAG_NAME&lt;/code&gt; environment variable to the tag name. Your pre-run commands or your Pulumi program can read it — for example, to stamp the release version onto a resource tag or an application config value.&lt;/p&gt;
&lt;h2 id="works-across-every-vcs-integration"&gt;Works across every VCS integration&lt;/h2&gt;
&lt;p&gt;Tag triggers are available across all five version control integrations: &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/bitbucket/"&gt;Bitbucket&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;You can configure tag triggers wherever you manage deployment settings today — the &lt;a href="https://app.pulumi.com/signin"&gt;Pulumi Cloud console&lt;/a&gt;, the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/deployments/#patch-settings"&gt;REST API&lt;/a&gt;, or as code with the &lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/api-docs/deploymentsettings/"&gt;&lt;code&gt;pulumiservice.DeploymentSettings&lt;/code&gt;&lt;/a&gt; resource.&lt;/p&gt;
&lt;p&gt;To try it out:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Open a stack&amp;rsquo;s &lt;strong&gt;Settings &amp;gt; Deploy&lt;/strong&gt; tab in the Pulumi Cloud console.&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;Run updates for pushed tags&lt;/strong&gt; and add a tag filter such as &lt;code&gt;v*&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Push a tag — &lt;code&gt;git tag v1.0.0 &amp;amp;&amp;amp; git push origin v1.0.0&lt;/code&gt; — and watch the deployment run.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the full details, see the &lt;a href="https://www.pulumi.com/docs/deployments/concepts/triggers/#deploying-on-git-tags"&gt;deployment triggers&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/deployments/concepts/settings/#tag-filtering"&gt;tag filtering&lt;/a&gt; documentation. We&amp;rsquo;d love to hear how you put tag-based deployments to work.&lt;/p&gt;</description><author>Michael Fallihee</author><category>features</category><category>pulumi-cloud</category><category>announcements</category></item><item><title>Generating a Pulumi Provider from an OpenAPI Spec</title><link>https://www.pulumi.com/blog/generating-a-pulumi-provider-from-an-openapi-spec/</link><pubDate>Thu, 28 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/generating-a-pulumi-provider-from-an-openapi-spec/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/generating-a-pulumi-provider-from-an-openapi-spec/index.png" /&gt;
&lt;p&gt;Today, we are announcing v1.0 of the Pulumi Service Provider: a major milestone in managing Pulumi Cloud with Pulumi itself. The provider is now generated directly from the Pulumi Cloud OpenAPI specification, unlocking a dramatically expanded pulumiservice:api/* resource surface and enabling Pulumi Cloud capabilities to become available in the provider faster than ever before.&lt;/p&gt;
&lt;p&gt;This release also brings several major new capabilities to infrastructure as code, including fine-grained RBAC as code, Pulumi IDP as code, and audit log export as IaC. Together, these changes make the Pulumi Service Provider the most powerful and extensible way yet to manage and automate your Pulumi Cloud infrastructure.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-users"&gt;Why this matters for users&lt;/h2&gt;
&lt;p&gt;Historically, every new Pulumi Cloud feature implied a follow-up PR in the provider before that feature could be used from a Pulumi program. The provider was always slightly behind the API it wrapped, and entirely new capability areas could take months to land.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;api/*&lt;/code&gt; surface changes both timelines. Because the schema is derived from the OpenAPI spec at runtime:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Whole new resource families land in the provider the same release they reach Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;New fields, features, and enum values on existing resources show up across all five language SDKs the soon after they appear in the spec.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="whats-new-in-v10"&gt;What&amp;rsquo;s new in v1.0&lt;/h2&gt;
&lt;p&gt;v1.0 lifts whole capability areas of Pulumi Cloud into the &lt;code&gt;api/*&lt;/code&gt; surface, not just incremental field additions. None of it required bespoke provider code.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fine-grained RBAC as code.&lt;/strong&gt; Custom roles, organization membership, and team role assignments are now managed resources. For example, defining a read-only role and assigning it to a team:&lt;/p&gt;
&lt;div&gt;
&lt;pulumi-chooser type="language" options="typescript,python,go,csharp,java,yaml" mode=""&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="typescript" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;readOnly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;orgName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stack-reader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Read-only access to stacks across the org.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;uxPurpose&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;__type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PermissionDescriptorAllow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;permissions&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;stack:read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stack:list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;readOnlyForPlatform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;orgName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;teamName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;roleID&lt;/span&gt;: &lt;span class="kt"&gt;readOnly.roleID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="python" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;read_only&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pulumiservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;org_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;stack-reader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Read-only access to stacks across the org.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ux_purpose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;__type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PermissionDescriptorAllow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;permissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;stack:read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stack:list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumiservice&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;teams&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;readOnlyForPlatform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;org_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;team_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;read_only&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;role_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="go" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RoleArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OrgName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack-reader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Read-only access to stacks across the org.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;UxPurpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;__type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;PermissionDescriptorAllow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;permissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StringArray&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack:read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack:list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnlyForPlatform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RoleArgs&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;OrgName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TeamName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RoleID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RoleID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="csharp" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;readOnly&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OrgName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;stack-reader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Read-only access to stacks across the org.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UxPurpose&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Details&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ImmutableDictionary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;__type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;PermissionDescriptorAllow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;permissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;stack:read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;stack:list&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Ps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnlyForPlatform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OrgName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TeamName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RoleID&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RoleID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="java" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RoleArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack-reader&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Read-only access to stacks across the org.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uxPurpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;role&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;__type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;PermissionDescriptorAllow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;permissions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack:read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;stack:list&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api_teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Role&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;readOnlyForPlatform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pulumi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pulumiservice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;api_teams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;RoleArgs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;acme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;teamName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roleID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roleID&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pulumi-choosable type="language" values="yaml" mode=""&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:api:Role&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;acme&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;stack-reader&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Read-only access to stacks across the org.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;uxPurpose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;role&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;__type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;PermissionDescriptorAllow&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;stack:read&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;stack:list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readOnlyForPlatform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;pulumiservice:api/teams:Role&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;orgName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;acme&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;teamName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;platform&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;roleID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${readOnly.roleID}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pulumi-choosable&gt;
&lt;/div&gt;
&lt;/pulumi-chooser&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pulumi IDP as code.&lt;/strong&gt; &lt;code&gt;services:Service&lt;/code&gt; makes the &lt;a href="https://www.pulumi.com/docs/idp/"&gt;Pulumi IDP&lt;/a&gt; catalog manageable from your Pulumi programs, surfaced the same release IDP ships in Pulumi Cloud. Platform teams can publish service definitions as code rather than only through the IDP console.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Audit-log export as IaC.&lt;/strong&gt; &lt;code&gt;AuditLogExportConfiguration&lt;/code&gt; brings audit-log export sinks under Pulumi management with a real destroy path.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Pulumi Cloud&amp;rsquo;s OpenAPI document (published at &lt;a href="https://api.pulumi.com/api/openapi/pulumi-spec.json"&gt;https://api.pulumi.com/api/openapi/pulumi-spec.json&lt;/a&gt;) is embedded in the provider binary at build time, so the provider version you pin is the API surface you get. Preview and update are deterministic, and a version released today will still behave the same way years from now. Alongside the spec, the runtime loads a small companion metadata file that captures the Pulumi-specific semantics OpenAPI can&amp;rsquo;t express: which endpoints pair into a single resource, what a resource&amp;rsquo;s ID looks like, and which response fields are secrets that arrive exactly once at create time. That metadata is what lets &lt;code&gt;api/*&lt;/code&gt; resources behave as expected.&lt;/p&gt;
&lt;p&gt;Most of that metadata is auto-derived by a scaffolder, but the editorial layer, including resource descriptions, examples, and the v0 aliases that make migration safe, stays handmade. Any human override is pinned across regeneration so a future spec change can&amp;rsquo;t quietly override it. The language SDKs are still generated against the runtime schema, so new fields and enum values reach typed SDKs in all five languages the moment the spec ships.&lt;/p&gt;
&lt;h2 id="what-the-api-namespace-covers"&gt;What the api namespace covers&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;api&lt;/code&gt; namespace already spans most of Pulumi Cloud&amp;rsquo;s resource model.&lt;/p&gt;
&lt;p&gt;For resources that have an ancestor under &lt;code&gt;pulumiservice:index:*&lt;/code&gt;, the mapping lives in &lt;a href="https://github.com/pulumi/pulumi-pulumiservice/blob/main/docs/v0-api-coverage.md"&gt;&lt;code&gt;docs/v0-api-coverage.md&lt;/code&gt;&lt;/a&gt;. That file is auto-generated, so it stays in sync. Each &lt;code&gt;api/*&lt;/code&gt; resource ships hand-maintained per-language examples in TypeScript, Python, Go, .NET, Java, and YAML.&lt;/p&gt;
&lt;h2 id="what-to-know-before-adopting-the-preview"&gt;What to know before adopting the preview&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The pulumiservice:api:* resource surface is in preview. Resource shape and module layout may change before GA.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;The existing &lt;code&gt;pulumiservice:index:*&lt;/code&gt; resources remain supported.&lt;/strong&gt; They are not being deprecated as part of v1.0 and continue to be supported. Migration to &lt;code&gt;api/*&lt;/code&gt; is opt-in via Pulumi &lt;code&gt;aliases&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="try-it"&gt;Try it&lt;/h2&gt;
&lt;p&gt;If you want to take the expanded provider for a spin:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;a href="https://www.pulumi.com/registry/packages/pulumiservice/"&gt;Pulumi Registry page for &lt;code&gt;pulumiservice&lt;/code&gt;&lt;/a&gt; has install instructions for every language.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/pulumi/pulumi-pulumiservice/tree/main/examples/api"&gt;&lt;code&gt;examples/api/&lt;/code&gt;&lt;/a&gt; directory has runnable programs for each resource, in every supported language.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/pulumi/pulumi-pulumiservice"&gt;&lt;code&gt;pulumi-pulumiservice&lt;/code&gt; repo&lt;/a&gt; is open source if you want to read the runtime, the embedded spec, or the metadata file directly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Feedback during preview is very beneficial. Please open an issue &lt;a href="https://github.com/pulumi/pulumi-pulumiservice/issues"&gt;here&lt;/a&gt; if you run into any problems.&lt;/p&gt;</description><author>Luke Ward</author><category>pulumi-cloud</category></item><item><title>Introducing pulumi do: Direct Resource Operations for Any Cloud</title><link>https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-do-direct-resource-operations/index.png" /&gt;
&lt;p&gt;Infrastructure as code is the right model for production systems. State tracking, drift detection, and repeatable deployments all matter when you&amp;rsquo;re managing real workloads.&lt;/p&gt;
&lt;p&gt;But sometimes, you also need a quick, one-off interaction with the cloud: create a bucket or a database, look up a VPC, delete a stray resource.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re introducing &lt;code&gt;pulumi do&lt;/code&gt;, a new command for direct resource operations. With &lt;code&gt;pulumi do&lt;/code&gt;, you can create, read, update, delete, and query any cloud resource from the terminal with a single command, across thousands of Pulumi-supported providers — no project, code, or state required.&lt;/p&gt;
&lt;h2 id="the-problem-sometimes-iac-is-more-than-you-need"&gt;The problem: Sometimes IaC is more than you need&lt;/h2&gt;
&lt;p&gt;When you&amp;rsquo;re managing production workloads, IaC is the proven solution. Code lets you declare complex systems, state tracking catches drift before it becomes a problem, dependency graphs sequence changes safely, and policy keeps everything in bounds. That full lifecycle, especially with the backing of a platform like Pulumi Cloud, is exactly what you want to build systems that scale.&lt;/p&gt;
&lt;p&gt;But when you (or your coding agent) need an ad-hoc Postgres database, the simplest path with IaC still takes several steps: make a directory, create a project, configure your credentials, write the code, preview, deploy. It works, but it&amp;rsquo;s not always necessary for what should be a simple operation. &lt;code&gt;pulumi do&lt;/code&gt; collapses all of those steps into one, using the same Pulumi providers, resource model, and ecosystem that powers the core Pulumi platform.&lt;/p&gt;
&lt;p&gt;Resource creation is also only part of the problem. As Joe laid out in &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;The Agentic Infrastructure Era&lt;/a&gt;, the real challenge for AI agents isn&amp;rsquo;t with code or CLI commands, it&amp;rsquo;s with everything else: getting a cloud account, resolving credentials, wiring configuration across multiple services. &lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/agent-accounts/"&gt;Agent accounts&lt;/a&gt;, also &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;released this week&lt;/a&gt;, simplify this by letting an agent provision its own ephemeral Pulumi Cloud account, and &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; takes care of consolidating credentials across providers. Together, with &lt;code&gt;pulumi do&lt;/code&gt;, agents can now go from zero to deployed infrastructure without requiring a human in the loop — and when that one-off resource needs to grow into a more permanent system, there&amp;rsquo;s a clear graduation path back to full Pulumi IaC.&lt;/p&gt;
&lt;h2 id="what-it-looks-like"&gt;What it looks like&lt;/h2&gt;
&lt;p&gt;As an example, say you wanted to provision an S3 bucket. With the AWS CLI, you&amp;rsquo;d need to assemble an &lt;code&gt;aws s3api create-bucket&lt;/code&gt; invocation with the right set of command-line flags, region constraints, a globally unique name, and so on. With &lt;code&gt;pulumi do&lt;/code&gt;, it&amp;rsquo;s just this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That might not look all that different on the surface — but because you&amp;rsquo;re using the Pulumi engine and resource model, you can provide a minimal set of input properties, take advantage of provider-defined defaults, and use Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/names/"&gt;auto-naming&lt;/a&gt; feature to give the bucket a unique name automatically:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This will create aws:s3/bucket:Bucket with the following inputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucket&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-279ea56&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;tagsAll&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Please confirm that this is what you&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;d like to &lt;span class="k"&gt;do&lt;/span&gt; by typing &lt;span class="sb"&gt;`&lt;/span&gt;yes&lt;span class="sb"&gt;`&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Answer &lt;code&gt;yes&lt;/code&gt; (or just pass &lt;code&gt;--yes&lt;/code&gt;), and you&amp;rsquo;re done. To delete the bucket:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket delete bucket-279ea56 --yes
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Need to look up an existing resource? Use a &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/provider-functions/"&gt;provider function&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:ec2:getVpc --default
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;arn&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;arn:aws:ec2:us-west-2:663782525873:vpc/vpc-d7b311af&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;cidrBlock&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;172.31.0.0/16&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableDnsHostnames&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableDnsSupport&amp;#34;&lt;/span&gt;: true,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;enableNetworkAddressUsageMetrics&amp;#34;&lt;/span&gt;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;vpc-d7b311af&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same CLI, same output contract, same provider ecosystem.&lt;/p&gt;
&lt;h3 id="the-command-shape"&gt;The command shape&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;do&lt;/code&gt; command accepts a Pulumi resource type, or &lt;a href="https://www.pulumi.com/docs/iac/concepts/resources/names/#types"&gt;&lt;em&gt;type token&lt;/em&gt;&lt;/a&gt;, to determine the action to take. Type tokens have the form &lt;code&gt;&amp;lt;package:module:resource&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;aws:s3:Bucket&lt;/code&gt; refers to the &lt;a href="https://www.pulumi.com/registry/packages/aws/api-docs/s3/bucket/"&gt;Amazon S3 Bucket resource&lt;/a&gt; that belongs to the &lt;code&gt;s3&lt;/code&gt; module of the &lt;code&gt;aws&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;You can also provide a portion of the token to help you find what you&amp;rsquo;re looking for without ever having to leave the terminal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Functions and resources &lt;span class="k"&gt;for&lt;/span&gt; the s3 module.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Run &lt;span class="s1"&gt;&amp;#39;pulumi do &amp;lt;module/resource/function&amp;gt; --help&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; more details on usage.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Functions:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getAccessPoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getAccountPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getBucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:getBucketObject
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Resources:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AccessPoint
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AccountPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:AnalyticsConfiguration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; aws:s3:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-d20976f
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;arn&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;arn:aws:s3:::bucket-d20976f&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucket&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-d20976f&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucketDomainName&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;bucket-d20976f.s3.amazonaws.com&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;bucketNamespace&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;global&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The package, module, and resource/function segments all come directly from the Pulumi provider schema, so &lt;code&gt;--help&lt;/code&gt; works at every level of the tree. Pass a package name, optional module, and optional function or resource type, and &lt;code&gt;do&lt;/code&gt; returns the appropriate level of detail.&lt;/p&gt;
&lt;p&gt;You can also provide the input properties of a resource in a YAML or JSON file with the &lt;code&gt;--input&lt;/code&gt; option. To create a container service in Google Cloud Run for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# service.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-central1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;deletionProtection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-docker.pkg.dev/cloudrun/container/hello&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; gcp:cloudrunv2:Service create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --input yaml &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --input-file service.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;This will create gcp:cloudrunv2/service:Service with the following inputs:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;deletionProtection&amp;#34;&lt;/span&gt;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;location&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-central1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;service-b8af752&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;template&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;containers&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;image&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-docker.pkg.dev/cloudrun/container/hello&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;createTime&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2026-05-22T23:00:22.415839Z&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;urls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://service-b8af752-921927215178.us-central1.run.app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://service-b8af752-ctnulmzwoa-uc.a.run.app&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="resource-operations"&gt;Resource operations&lt;/h3&gt;
&lt;p&gt;Most resources support the full set of CRUD operations — create, read, update, delete, and list — directly from the CLI. Each operation maps to a provider CRUD method using the same provider logic a full Pulumi program would use, and resources are addressable by their cloud provider IDs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a resource&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket create --yes &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bucket-4f5cb22
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Fetch it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-4f5cb22 &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.hostedZoneId&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Z3BJ6K6RIION7M
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Update/patch it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket patch bucket-4f5cb22 --input yaml --input-file tags.yaml
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket &lt;span class="nb"&gt;read&lt;/span&gt; bucket-4f5cb22 &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s2"&gt;&amp;#34;.tags&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;key&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;value&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Delete it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws:s3:Bucket delete bucket-4f5cb22
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="provider-configuration"&gt;Provider configuration&lt;/h3&gt;
&lt;p&gt;Today, &lt;code&gt;pulumi do&lt;/code&gt; resolves provider configuration — for example, applying your AWS credentials — using environment variables or credential files as supported by each individual Pulumi provider. See the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; for provider-specific configuration details.&lt;/p&gt;
&lt;h2 id="designed-for-humans-and-agents"&gt;Designed for humans and agents&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ve designed &lt;code&gt;pulumi do&lt;/code&gt; to serve humans and coding agents equally well, guided by three fundamental ideas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent command structure across every provider.&lt;/strong&gt; The &lt;code&gt;do &amp;lt;package:module:type&amp;gt; &amp;lt;operation&amp;gt;&lt;/code&gt; pattern is the same for AWS, Azure, Google Cloud, Kubernetes, Cloudflare, Datadog, and every provider, including packages containing higher-level &lt;a href="https://www.pulumi.com/docs/iac/concepts/components/"&gt;component resources&lt;/a&gt;. Once an agent learns that pattern, it applies across the board.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Predictable output contract.&lt;/strong&gt; JSON on stdout, progress on stderr, consistent exit codes. An agent can parse the result programmatically without scraping human-formatted tables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A single CLI command that works across every cloud.&lt;/strong&gt; Many cloud and SaaS providers don&amp;rsquo;t have a full CLI at all. &lt;code&gt;pulumi do&lt;/code&gt; generates commands from the provider schema, so if a Pulumi provider exists for it, the CLI just works. Neither humans nor agents need to install, learn, or even know about cloud provider-specific tooling.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-next"&gt;What&amp;rsquo;s next&lt;/h2&gt;
&lt;p&gt;Resource operations and provider functions are the foundation. The &lt;code&gt;pulumi do&lt;/code&gt; roadmap extends the same direct-operation model with credential management, state tracking, and a path to full IaC.&lt;/p&gt;
&lt;h3 id="unified-credentials-with-pulumi-esc"&gt;Unified credentials with Pulumi ESC&lt;/h3&gt;
&lt;p&gt;One of the hardest parts of multi-cloud operations is credential management. Every provider has its own authentication scheme, environment variables, and session lifecycle. An agent working across AWS, Cloudflare, and Datadog today manages three separate credential mechanisms.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re building &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; integration into &lt;code&gt;pulumi do&lt;/code&gt; so you can manage credentials in one place and resolve them everywhere. ESC handles credential resolution (including OIDC-based dynamic credential generation and short-lived tokens) across all of your providers. Name the credential set, reference it, and ESC does the rest, with rotation, RBAC, and audit built in.&lt;/p&gt;
&lt;h3 id="cross-resource-references"&gt;Cross-resource references&lt;/h3&gt;
&lt;p&gt;Real infrastructure has dependencies — subnets need VPCs, security group rules need their security groups, and so on. When you&amp;rsquo;re building resources one at a time, those references need to flow between commands somehow.&lt;/p&gt;
&lt;p&gt;A future version of &lt;code&gt;pulumi do&lt;/code&gt; will let resource inputs reference outputs from previously created resources, allowing the CLI to resolve them automatically and preserve the dependency graph. Later, when the time comes to graduate to a full IaC program, the generated code contains proper resource references rather than hard-coded strings.&lt;/p&gt;
&lt;h3 id="stateful-mode-and-the-graduation-path"&gt;Stateful mode and the graduation path&lt;/h3&gt;
&lt;p&gt;Today, &lt;code&gt;pulumi do&lt;/code&gt; is stateless. Each command runs independently. A planned stateful mode will persist resource state across operations, enabling drift detection, lifecycle management, and a graduation path to full infrastructure as code.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what we&amp;rsquo;re planning:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Zero setup.&lt;/strong&gt; Your first &lt;code&gt;pulumi do&lt;/code&gt; implicitly creates a project and stack. No manual initialization.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Accumulate resources.&lt;/strong&gt; Each operation stores resource state. After a few commands, you have a lightweight representation of your infrastructure.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Eject to a full project.&lt;/strong&gt; When the time comes, generate a Pulumi project in your chosen language with all resources imported and dependency graphs intact.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Connect to Pulumi Cloud.&lt;/strong&gt; Layer on governance, compliance, team collaboration, and deployment automation through &lt;a href="https://www.pulumi.com/product/"&gt;Pulumi Cloud&lt;/a&gt;. Resources created via &lt;code&gt;pulumi do&lt;/code&gt; can be governed by &lt;a href="https://www.pulumi.com/product/insights-governance/"&gt;Pulumi Insights&lt;/a&gt; from day one, even before you opt into full IaC.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This path works because &lt;code&gt;pulumi do&lt;/code&gt; uses the same providers, resource types, and property schemas as every other &lt;code&gt;pulumi&lt;/code&gt; operation. Provisioned cloud resources stay where they are as management capabilities are added as needed.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi do&lt;/code&gt; ships as a research preview in &lt;a href="https://github.com/pulumi/pulumi/releases/tag/v3.242.0"&gt;Pulumi CLI v3.242.0&lt;/a&gt; and later. Install or update the CLI, install a provider plugin, and start running commands. The &lt;a href="https://www.pulumi.com/docs/iac/cli/direct-resource-operations/"&gt;documentation&lt;/a&gt; has the full reference.&lt;/p&gt;
&lt;p&gt;We can&amp;rsquo;t wait to hear your feedback. &lt;a href="https://www.pulumi.com/docs/install/"&gt;Give it a try today&lt;/a&gt;, tell us what works (and what doesn&amp;rsquo;t), and help shape the CLI that agents and humans both reach for first.&lt;/p&gt;</description><author>Fraser Waters</author><author>Pat Gavlin</author><author>Arun Loganathan</author><author>Christian Nunciato</author><category>features</category><category>pulumi-cli</category><category>ai-agents</category><category>product-launches</category></item><item><title>Bringing Neo to GitHub and Slack</title><link>https://www.pulumi.com/blog/neo-github-slack/</link><pubDate>Thu, 21 May 2026 08:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-github-slack/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-github-slack/index.png" /&gt;
&lt;p&gt;This week, &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt; started working in two more places: GitHub and Slack. The agent that already runs Pulumi tasks from the Cloud console and the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;terminal&lt;/a&gt; now participates in the threads where your team discusses changes.&lt;/p&gt;
&lt;p&gt;Mention &lt;code&gt;@pulumi-neo&lt;/code&gt; in a &lt;a href="https://www.pulumi.com/docs/ai/neo/code-reviews/"&gt;pull request or issue&lt;/a&gt; and Neo replies in the thread. Mention &lt;code&gt;@Neo&lt;/code&gt; in a &lt;a href="https://www.pulumi.com/docs/ai/integrations/slack/"&gt;Slack channel&lt;/a&gt; and Neo starts a &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/"&gt;task&lt;/a&gt;, continuing the conversation as you reply.&lt;/p&gt;
&lt;h2 id="neo-in-github"&gt;Neo in GitHub&lt;/h2&gt;
&lt;p&gt;Mention &lt;code&gt;@pulumi-neo&lt;/code&gt; in a pull request description, a top-level or inline review comment, or an issue. Neo sees the diff, the stacks linked to the repository, and their current state. Reviewers can ask Neo to walk through what a proposed change does, including resources that change in stacks the PR doesn&amp;rsquo;t touch directly. Responses land in the same thread, so the analysis becomes part of the review record and any follow-up stays with it.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Delegating a GitHub issue to Neo"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-github.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="neo-in-slack"&gt;Neo in Slack&lt;/h2&gt;
&lt;p&gt;Mention &lt;code&gt;@Neo&lt;/code&gt; in any channel where Neo has been added, and Neo starts a task in the thread. The reply lands in the same thread, and follow-up messages continue the conversation there. The rest of the channel can see what was asked and what Neo found. Neo has the same capabilities here as in the Pulumi Cloud console or the terminal: check stack state, investigate failures, walk through what a change will do, or carry out actions the team has approved.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Tagging Neo for help with an issue in Slack"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-slack.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="integrations-in-action"&gt;Integrations in action&lt;/h2&gt;
&lt;p&gt;A teammate posts in &lt;code&gt;#platform-engineering&lt;/code&gt;: &amp;ldquo;API latency p95 has been climbing for two days, nobody can figure out why.&amp;rdquo; You reply:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; @Neo check the production API stack. Anything change in the last 72 hours?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo starts a task in the thread, walks the stack history, and finds a configuration change to the load balancer&amp;rsquo;s idle-timeout setting that landed Friday afternoon. It posts the change, who deployed it, and when. The rest of the channel sees the finding without you having to retell it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; @Neo open a PR to revert idle-timeout to the previous value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo edits the stack&amp;rsquo;s Pulumi program, runs &lt;code&gt;pulumi preview&lt;/code&gt; to confirm the change touches only the load balancer, and opens a pull request with the diff and the preview output. A reviewer pulls it up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reviewer:&lt;/strong&gt; @pulumi-neo what else does this change affect downstream?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo replies in the same review thread with the resources that change: the listener config and the target group health check. The reviewer reads, approves, and the change ships.&lt;/p&gt;
&lt;p&gt;The investigation moved from Slack to GitHub, and both threads keep the record.&lt;/p&gt;
&lt;h2 id="permissions-and-governance"&gt;Permissions and governance&lt;/h2&gt;
&lt;p&gt;Whether the conversation starts in GitHub or Slack, Neo runs with the &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;RBAC permissions&lt;/a&gt; of your Pulumi Cloud user. Stack-level controls, organization-level guardrails, and audit logging apply the same way they do for a task started from the console. Starting a conversation in a new place doesn&amp;rsquo;t grant Neo new permissions; it just changes where the conversation happens.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Both integrations are available now for Neo-enabled organizations. The &lt;a href="https://www.pulumi.com/docs/ai/neo/code-reviews/"&gt;Code Reviews docs&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/integrations/slack/"&gt;Slack integration docs&lt;/a&gt; cover the one-time setup. From there, every engineer with a linked Pulumi Cloud identity can mention Neo from the threads they already work in.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo CLI launch post&lt;/a&gt; for Neo&amp;rsquo;s new home in the terminal, and the &lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integrations post&lt;/a&gt; for the MCP servers and cloud CLIs that ship with this release.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for places we should put Neo next, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Neo Automations: Scheduled Tasks Shipped as Pull Requests</title><link>https://www.pulumi.com/blog/neo-automations/</link><pubDate>Thu, 21 May 2026 07:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/neo-automations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-automations/index.png" /&gt;
&lt;p&gt;Recurring platform work slips: provider versions fall behind, drift accumulates between checks, and the quarterly audit keeps getting pushed back another month. &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt; can now run any &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/"&gt;task&lt;/a&gt; on a cadence you set, opening a pull request for each run.&lt;/p&gt;
&lt;h2 id="automations-in-action"&gt;Automations in action&lt;/h2&gt;
&lt;p&gt;Your platform team runs stacks across staging and production, and the &lt;a href="https://www.pulumi.com/registry/packages/aws/"&gt;AWS&lt;/a&gt;, &lt;a href="https://www.pulumi.com/registry/packages/gcp/"&gt;GCP&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/registry/packages/kubernetes/"&gt;Kubernetes&lt;/a&gt; providers keep shipping new versions. Nobody has time to bump them stack by stack.&lt;/p&gt;
&lt;p&gt;You write one automation:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every Monday at 8 AM, check the &lt;code&gt;infra/&lt;/code&gt; project for stacks where the AWS, GCP, or Kubernetes provider is more than two minor versions behind. For each one, bump the out-of-date provider, run &lt;code&gt;pulumi preview&lt;/code&gt;, and open a PR if the preview is clean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Monday morning, Neo runs the prompt. It finds three stacks behind on the AWS provider, edits each program, runs preview, and opens a PR for each clean run. You review the PRs like you would any other dependency bump, merge them, and Neo runs again next Monday.&lt;/p&gt;
&lt;h2 id="what-automations-are-for"&gt;What automations are for&lt;/h2&gt;
&lt;p&gt;The launch includes four built-in templates: a provider freshness check, an encryption audit, a backup audit, and an activity digest. You can also skip the templates and write your own prompt.&lt;/p&gt;
&lt;p&gt;Pick from hourly, daily, weekdays, or weekly cadences. Each automation gets its own page in the &lt;strong&gt;Automations&lt;/strong&gt; tab, where you can edit the prompt, change the schedule, run it once on demand, or pause it.&lt;/p&gt;
&lt;h2 id="safe-by-default"&gt;Safe by default&lt;/h2&gt;
&lt;p&gt;Automations default to two settings that fit recurring work. Approval mode is &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#task-modes"&gt;&lt;strong&gt;auto&lt;/strong&gt;&lt;/a&gt;, so a run doesn&amp;rsquo;t wait for human confirmation between steps. Permission mode is &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#task-modes"&gt;&lt;strong&gt;read-only&lt;/strong&gt;&lt;/a&gt;, so a run can read state and propose changes through pull requests but can&amp;rsquo;t apply changes directly. You can override either default per automation.&lt;/p&gt;
&lt;h2 id="how-automations-fit-with-the-rest-of-neo"&gt;How automations fit with the rest of Neo&lt;/h2&gt;
&lt;p&gt;A scheduled task uses the same context as an interactive Neo task. &lt;a href="https://www.pulumi.com/docs/ai/neo/settings/"&gt;Custom Instructions&lt;/a&gt; at the organization and project level apply, so a scheduled run respects the same naming conventions, tagging policies, and architecture rules your team has written down.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/"&gt;MCP integrations&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/"&gt;CLI integrations&lt;/a&gt; work in scheduled tasks the same way they work in interactive ones, so a weekly drift check can query AWS through the &lt;code&gt;aws&lt;/code&gt; CLI, file &lt;a href="https://linear.app/"&gt;Linear&lt;/a&gt; issues, and link related &lt;a href="https://www.pagerduty.com/"&gt;PagerDuty&lt;/a&gt; incidents. Scheduled tasks also run with the &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;RBAC permissions&lt;/a&gt; of the user who scheduled them, checked at run time; if permissions change between scheduling and execution, the new permissions apply.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Open Neo in &lt;a href="https://www.pulumi.com/product/"&gt;Pulumi Cloud&lt;/a&gt;, switch to the &lt;strong&gt;Automations&lt;/strong&gt; tab, and pick a template or write your own prompt. The &lt;a href="https://www.pulumi.com/docs/ai/neo/automations/"&gt;automations docs&lt;/a&gt; cover the form, scheduling options, and per-automation overrides.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/neo-automations/neo-freshness.check.png" alt="Setting up a scheduled task for Pulumi Neo"&gt;&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, and the &lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integrations post&lt;/a&gt; for the third-party tools and CLIs your automations can use.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for automations that&amp;rsquo;d make Neo even better, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category></item><item><title>Neo, Now in the Terminal</title><link>https://www.pulumi.com/blog/pulumi-neo-cli/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-neo-cli/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-neo-cli/index.png" /&gt;
&lt;p&gt;Since launching &lt;a href="https://www.pulumi.com/blog/pulumi-neo/"&gt;Pulumi Neo&lt;/a&gt;, over 4,500 organizations have used it to delegate real infrastructure work: scaffolding, migrating, investigating, operationalizing, and more. Though that usage has come entirely through Pulumi Cloud, we know a large portion of Pulumi users live in the terminal, and increasingly that&amp;rsquo;s where AI tools run too. Now we&amp;rsquo;re bringing Neo there.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; brings the same Neo experience you&amp;rsquo;ve had in Pulumi Cloud to your terminal. Running locally means there&amp;rsquo;s no separate branch to push, no credentials to provision, and no context to paste: Neo picks up the setup you already have.&lt;/p&gt;
&lt;p&gt;&lt;img src="tui.png" alt="pulumi neo working through a Kubernetes cluster check, with Flux GitOps state verified and a TODO list in progress"&gt;&lt;/p&gt;
&lt;h2 id="what-local-execution-unlocks"&gt;What local execution unlocks&lt;/h2&gt;
&lt;p&gt;Neo inherits your setup when it runs locally. The CLIs you&amp;rsquo;ve authenticated, the environment variables and kubeconfigs you&amp;rsquo;ve configured, and the project you&amp;rsquo;re editing right now are all available without any setup on your part. That means Neo can run the same commands you would, against the same systems you have access to.&lt;/p&gt;
&lt;p&gt;That makes &lt;code&gt;pulumi neo&lt;/code&gt; a fit for paired, interactive sessions where you and Neo work through a problem together. For asynchronous, autonomous tasks you set up and come back to, Pulumi Cloud Neo is still the surface to reach for. Both reach the same Neo.&lt;/p&gt;
&lt;p&gt;You can also hand tasks to Neo from other agent sessions. Simply ask your agent, such as Claude Code or Codex, to hand the task off to Neo, and the &lt;a href="https://github.com/pulumi/agent-skills/tree/main/delegation"&gt;Neo handoff skill&lt;/a&gt; packages the current thread (goal, repo pointers, conversation summary) and starts a Neo task using &lt;code&gt;pulumi neo&lt;/code&gt; under the hood. This works anywhere skills are supported, without leaving your current session.&lt;/p&gt;
&lt;h2 id="what-carries-over"&gt;What carries over&lt;/h2&gt;
&lt;p&gt;Local tools and context are what&amp;rsquo;s new. The full set of controls you have in Pulumi Cloud Neo applies in the terminal: approval modes (manual, balanced, auto) for tool calls, permission modes (default, read-only) for what Neo can change, and &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#plan-mode"&gt;Plan Mode&lt;/a&gt; for research and planning before execution.&lt;/p&gt;
&lt;p&gt;Integrations carry over too. The &lt;a href="https://www.pulumi.com/blog/neo-integration-catalog/"&gt;integration catalog&lt;/a&gt; (connectors to Atlassian, Datadog, Linear, PagerDuty, and others) works the same way from the terminal. Identity, RBAC, and audit all run through your &lt;code&gt;pulumi login&lt;/code&gt;, the same way they do in the console. See the &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo docs&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; ships with the latest Pulumi CLI. To start a session:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Authenticate to Pulumi Cloud with &lt;code&gt;pulumi login&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi neo&lt;/code&gt;, or pass an initial prompt: &lt;code&gt;pulumi neo &amp;quot;what's in this stack?&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;pulumi neo&lt;/code&gt; is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;broader launch&lt;/a&gt; on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;agentic infrastructure&lt;/a&gt;. See the &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_neo/"&gt;&lt;code&gt;pulumi neo&lt;/code&gt; command reference&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo docs&lt;/a&gt; for details. &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;10 things you can do with Neo&lt;/a&gt; is a good starting point for tasks to try. The &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; is the place for questions and feedback.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category><category>pulumi-cli</category></item><item><title>Neo Integrations: MCP Servers and Cloud CLIs</title><link>https://www.pulumi.com/blog/neo-integrations/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-integrations/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-integrations/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;Pulumi Neo&lt;/a&gt; already understands your infrastructure: your code, your stacks, your state. Today we&amp;rsquo;re launching new capabilities that extend Neo&amp;rsquo;s reach in two directions: into the third-party systems your team uses to plan and observe, and out to the cloud CLIs that actually drive your infrastructure.&lt;/p&gt;
&lt;p&gt;The first half is MCP integrations: connections to &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#atlassian-jira-and-confluence"&gt;Atlassian&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#datadog"&gt;Datadog&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#honeycomb"&gt;Honeycomb&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#linear"&gt;Linear&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#pagerduty"&gt;PagerDuty&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#supabase"&gt;Supabase&lt;/a&gt; that show up as tools Neo can call during a &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/"&gt;task&lt;/a&gt;. The second half is CLI integrations: scopable access to &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/#supported-clis"&gt;&lt;code&gt;aws&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/#supported-clis"&gt;&lt;code&gt;gcloud&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/#supported-clis"&gt;&lt;code&gt;az&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/#supported-clis"&gt;&lt;code&gt;kubectl&lt;/code&gt;&lt;/a&gt;. Both are configured once at the org level and available to every Neo task in the organization.&lt;/p&gt;
&lt;h2 id="integrations-in-action"&gt;Integrations in action&lt;/h2&gt;
&lt;p&gt;A PagerDuty alert just fired: RDS storage on &lt;code&gt;payments-prod&lt;/code&gt; is at 90% and climbing. You want to know how fast, and whether you can buy yourself any runway before it fills.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; Neo, RDS storage on &lt;code&gt;payments-prod&lt;/code&gt; just paged at 90%. How fast is it growing, and what do we have configured?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo pulls the active incident from PagerDuty, decides on its own to check Datadog for the storage-utilization curve over the last 30 days, and runs &lt;code&gt;aws rds describe-db-instances --db-instance-identifier payments-prod&lt;/code&gt; through your &lt;code&gt;production-aws&lt;/code&gt; CLI integration (the name your org gave its production AWS credentials). The database has been growing about 5 GB a day. The instance has &lt;code&gt;AllocatedStorage&lt;/code&gt; at 200 GB and &lt;code&gt;MaxAllocatedStorage&lt;/code&gt; also at 200, so storage autoscaling is effectively disabled. At current growth, the disk fills in three days.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; Bump max allocated storage to 500. Open a PR.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo edits the &lt;code&gt;payments&lt;/code&gt; stack&amp;rsquo;s Pulumi program to raise &lt;code&gt;maxAllocatedStorage&lt;/code&gt; from 200 to 500 on the RDS instance, runs &lt;code&gt;pulumi preview&lt;/code&gt; to confirm the change is scoped to that one resource, and opens a pull request with the diff, the preview output, and links to the PagerDuty incident and the Datadog graph. You review the PR and merge it. Pulumi applies the change, and Neo posts the resolution back to PagerDuty.&lt;/p&gt;
&lt;p&gt;With three integrations and one conversation, the change is reviewed, shipped, and the alert resolved a few minutes later.&lt;/p&gt;
&lt;h2 id="mcp-integrations-context-from-your-existing-tools"&gt;MCP integrations: context from your existing tools&lt;/h2&gt;
&lt;p&gt;The launch catalog covers six services that show up most often in infrastructure investigations: &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#atlassian-jira-and-confluence"&gt;Atlassian&lt;/a&gt; for Jira issues and Confluence runbooks, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#datadog"&gt;Datadog&lt;/a&gt; for metrics and logs, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#honeycomb"&gt;Honeycomb&lt;/a&gt; for traces, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#linear"&gt;Linear&lt;/a&gt; for issue tracking, &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#pagerduty"&gt;PagerDuty&lt;/a&gt; for incidents and on-call schedules, and &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/#supabase"&gt;Supabase&lt;/a&gt; for managed database changes. Each connects Neo to a remote MCP server hosted by the provider, so the agent has access to the full set of tools the vendor chooses to expose.&lt;/p&gt;
&lt;p&gt;Integrations can be enabled by organization administrators on the Neo Settings page. Once configured, they&amp;rsquo;re available to every Neo task in your organization.&lt;/p&gt;
&lt;p&gt;&lt;img src="mcp-integrations.png" alt="Neo Settings showing the six available MCP integrations: Atlassian, Datadog, Honeycomb, Linear, PagerDuty, and Supabase"&gt;&lt;/p&gt;
&lt;h2 id="cli-integrations-live-cloud-insights"&gt;CLI integrations: live cloud insights&lt;/h2&gt;
&lt;p&gt;CLI integrations cover what MCP doesn&amp;rsquo;t reach: live cloud insights. With AWS, GCP, Azure, or Kubernetes connected, Neo can check live database utilization, look up the current state of a running service, verify a service quota before scaling, or reach into resources that aren&amp;rsquo;t managed by any Pulumi stack.&lt;/p&gt;
&lt;p&gt;An admin enables a CLI integration the same way as an MCP one, from your org&amp;rsquo;s Neo settings. Each integration gets a name your team chooses, like &lt;code&gt;production-aws&lt;/code&gt; or &lt;code&gt;staging-gcloud&lt;/code&gt;, and tasks reference that name to tell Neo which environment to reach into. You can connect multiple instances of the same CLI (for example, &lt;code&gt;production-aws&lt;/code&gt; and &lt;code&gt;staging-aws&lt;/code&gt;) so Neo can investigate staging without touching production. Credentials are backed by &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environments your org owns; the &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/"&gt;CLI integrations docs&lt;/a&gt; walk through setup.&lt;/p&gt;
&lt;p&gt;&lt;img src="cli-integrations.png" alt="Neo Settings CLI tools tab with two connected AWS and Kubernetes integrations and four available CLI types: AWS, Google Cloud, Azure, and Kubernetes"&gt;&lt;/p&gt;
&lt;h2 id="per-task-control-and-failure-handling"&gt;Per-task control and failure handling&lt;/h2&gt;
&lt;p&gt;Both surfaces default to org-wide availability, with per-task overrides. Before starting a task, you can toggle individual MCP integrations off. The toggles only affect that task; the org-level configuration is unchanged.&lt;/p&gt;
&lt;p&gt;&lt;img src="per-task-toggles.png" alt="Neo task composer showing the Integrations menu with toggles for the Linear MCP server and two connected CLI integrations"&gt;&lt;/p&gt;
&lt;p&gt;Failures behave the same way for both. If an integration can&amp;rsquo;t be reached, Neo logs a warning, skips it, and continues with the rest. A single broken integration doesn&amp;rsquo;t stop a task. CLI integration connect and disconnect events go to your organization&amp;rsquo;s audit log, and Neo&amp;rsquo;s individual CLI calls appear in the task transcript alongside its other tool calls.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Both MCP and CLI integrations are available now for Neo-enabled organizations. Open your org&amp;rsquo;s Neo settings, connect the MCP server or CLI of your choice, and let Neo do the next investigation against the tools you already use. The &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/mcp/"&gt;MCP integrations docs&lt;/a&gt; and &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/cli/"&gt;CLI integrations docs&lt;/a&gt; walk through credential setup for each one, and the &lt;a href="https://www.pulumi.com/docs/ai/neo/integrations/"&gt;Neo integrations hub&lt;/a&gt; ties it all together.&lt;/p&gt;
&lt;p&gt;Today&amp;rsquo;s launch is part of a &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;bigger story&lt;/a&gt;. Read our launch-day piece on &lt;a href="https://www.pulumi.com/blog/the-agentic-infrastructure-era/"&gt;the agentic infrastructure era&lt;/a&gt; for the broader vision, and the &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo CLI launch post&lt;/a&gt; for Neo&amp;rsquo;s new home in the terminal.&lt;/p&gt;
&lt;p&gt;As always, we&amp;rsquo;d love to hear what you think — and if you have any suggestions for integrations that&amp;rsquo;d make Neo even better, file an issue in &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;pulumi-cloud-requests&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>ai</category><category>ai-agents</category><category>features</category><category>pulumi-neo</category><category>esc</category></item><item><title>Ten More Things You Can Do With Pulumi Neo</title><link>https://www.pulumi.com/blog/10-more-things-you-can-do-with-neo/</link><pubDate>Tue, 19 May 2026 05:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/10-more-things-you-can-do-with-neo/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/10-more-things-you-can-do-with-neo/index.png" /&gt;
&lt;p&gt;Last fall, after launching &lt;a href="https://www.pulumi.com/neo/"&gt;Pulumi Neo&lt;/a&gt;, we wrote up &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;10 things you could do with it&lt;/a&gt;. In the months that followed, as platform teams handed Neo more real work, we watched and listened, shipping a steady stream of features like &lt;a href="https://www.pulumi.com/blog/neo-plan-mode/"&gt;plan mode&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/neo-read-only-mode/"&gt;read-only mode&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/pulumi-neo-now-supports-agentsmd/"&gt;AGENTS.md&lt;/a&gt;, an &lt;a href="https://www.pulumi.com/blog/neo-integration-catalog/"&gt;integration catalog&lt;/a&gt;, &lt;a href="https://www.pulumi.com/blog/neo-migration/"&gt;cross-cloud migration&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/blog/neo-task-sharing/"&gt;task sharing&lt;/a&gt;. With &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;today&amp;rsquo;s release&lt;/a&gt;, Neo extends beyond the Pulumi Cloud console into the Pulumi CLI, GitHub, and Slack.&lt;/p&gt;
&lt;p&gt;So here are &lt;strong&gt;10 more&lt;/strong&gt; things you can do with Neo.&lt;/p&gt;
&lt;h2 id="1-deploy-your-app-to-aws-without-writing-iac"&gt;1. Deploy your app to AWS without writing IaC&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Hand Neo a repo. Neo picks the right services — ECS, AWS Fargate, ALB — writes the Pulumi, and opens a PR.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The cloud infrastructure part of getting a new service running, especially one in a new language, is always a few hours of boilerplate: a VPC and subnets, an IAM role, security groups, a load balancer, DNS, and a TLS cert.&lt;/p&gt;
&lt;p&gt;With Neo, that work collapses into a prompt. Point Neo at a repo and ask:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Deploy this app to AWS as a publicly accessible service.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/blog/neo-plan-mode/"&gt;Plan mode&lt;/a&gt; comes back with the resources Neo will create, named and sized: ECS running on AWS Fargate, an ALB, and the VPC wiring. Approve, and Neo writes the Pulumi program, runs a preview, and opens a PR. You, the human in the loop, merge it after review.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Neo deploying an app to AWS: prompt, plan mode, PR, public URL"
autoplay muted playsinline
loop &gt;
&lt;source src="deploy-to-aws2.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Neo planning a PR and deploying an app to AWS.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=I%27d&amp;#43;like&amp;#43;to&amp;#43;deploy&amp;#43;this&amp;#43;app&amp;#43;to&amp;#43;AWS.&amp;#43;Confirm&amp;#43;what&amp;#43;you%27ll&amp;#43;create." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Ask Neo to deploy your app to AWS and make a PR&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="2-diagnose-a-slow-api-from-metrics-logs-and-code"&gt;2. Diagnose a slow API from metrics, logs, and code&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Slow endpoints live at the seam between runtime metrics and the stack that runs them. Neo reads both and proposes a fix with the metric evidence as the rationale.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Production incidents often involve multiple tools. When the &lt;code&gt;checkout&lt;/code&gt; endpoint&amp;rsquo;s p95 latency climbs from 200ms to 1.2s, the metric is in Datadog, but the cause might be somewhere in your AWS account: maybe RDS is out of IOPS, maybe the connection pool is too small, maybe the autoscaler isn&amp;rsquo;t keeping up. Connecting &amp;ldquo;this metric looks bad&amp;rdquo; to a recent backend change and then to a one-line fix in your Pulumi program is an exercise in detective work.&lt;/p&gt;
&lt;p&gt;Neo&amp;rsquo;s &lt;a href="https://www.pulumi.com/blog/neo-integration-catalog/"&gt;integration catalog&lt;/a&gt; bridges this gap. With built-in Datadog APM, PagerDuty, and Honeycomb integrations sitting alongside your Pulumi state, Neo can read traces and metrics from the tools your team already uses and take action.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Find the scaling bottleneck on &lt;code&gt;/checkout&lt;/code&gt; from the last 7 days of metrics and propose a fix.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo pulls the metric history, matches the Datadog tag &lt;code&gt;db.cluster=checkout-rds&lt;/code&gt; to the RDS instance in your &lt;code&gt;prod-checkout&lt;/code&gt; Pulumi stack, and opens a PR with a Pulumi diff that bumps the storage IOPS and raises the connection-pool ceiling. You review and roll out the fix.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Enabling the Honeycomb integration in Neo"
autoplay muted playsinline
loop &gt;
&lt;source src="honey-comb.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Toggle on the Honeycomb integration so Neo can read traces and metrics alongside your Pulumi stacks.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;h2 id="3-automate-pagerduty-incident-response-from-slack"&gt;3. Automate PagerDuty incident response from Slack&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;A page comes in. You paste it into your on-call channel and tag Neo, and Neo replies with the cross-system view you&amp;rsquo;d otherwise spend the first 20 minutes assembling.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;On-call triage is often about getting up to speed quickly. You get paged because something is in the red, and you don&amp;rsquo;t know why.&lt;/p&gt;
&lt;p&gt;You mention Neo in the on-call Slack channel:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;@neo, what&amp;rsquo;s going on with this alert?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo starts querying metrics and traces. With PagerDuty and Datadog in the integration catalog, it correlates the alert with every deploy and stack change tagged with the alert&amp;rsquo;s service in the last hour, and finds the change that lines up:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Two deploys in the last hour touched services tagged &lt;code&gt;service:checkout&lt;/code&gt;: &lt;code&gt;checkout-api@a3f9c2&lt;/code&gt; (12 min ago, app-layer deploy) and Pulumi stack &lt;code&gt;prod-checkout-rds&lt;/code&gt; (45 min ago, decreased &lt;code&gt;max_connections&lt;/code&gt; from 200 → 100). p99 latency inflection at 14:03 lines up with the stack change. Likely cause: the connection-pool reduction is starving the API under current load.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You ask a couple of clarifying questions in-thread, then ask Neo to open a rollback PR against the Pulumi stack.&lt;/p&gt;
&lt;p&gt;&lt;img src="neo-integration-catalog.png" alt="Neo Settings → Integrations page: six integrations available with Authorize buttons for Atlassian, Datadog, Honeycomb, Linear, PagerDuty, and Supabase"&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Authorize PagerDuty and Datadog in Neo's settings. Neo can then read alerts in your on-call Slack channel, find the change that correlates, and open a PR when you ask.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;h2 id="4-implement-a-jira-or-linear-ticket-end-to-end"&gt;4. Implement a Jira or Linear ticket end-to-end&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Hand Neo a ticket number from Linear, Jira, or GitHub Issues. Neo reads the description and acceptance criteria, plans against your stack, and opens a PR.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Tickets often pile up not because they&amp;rsquo;re unimportant, but because they&amp;rsquo;re not urgent. Ongoing maintenance quietly accumulates. Bumping a provider version, centralizing secret management, working through small policy violations: each one matters, but none of them ever moves to the top of the queue. Explaining each one to an agent is its own overhead.&lt;/p&gt;
&lt;p&gt;The fix is letting Neo read the ticket itself. Connect Linear integration or Jira automation through the integration catalog (GitHub Issues works too), and Neo pulls the ticket the same way an engineer would: title, description, acceptance criteria.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Implement CAD-1234 in our payments stack.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo reads the ticket, plans against your existing stack, opens a PR, and drops a comment back on the ticket. The ticket and the PR end up linked, and your backlog shrinks.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Neo running locally in the Pulumi CLI: fielding a Linear issue, analyzing the codebase, and producing a PR that upgrades multiple projects to the latest Pulumi and AWS provider versions"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-linear.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Neo running locally in the Pulumi CLI: fielding a Linear issue, analyzing the codebase, and producing a PR that upgrades multiple projects to the latest Pulumi and AWS provider versions.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=I%27d&amp;#43;like&amp;#43;to&amp;#43;implement&amp;#43;a&amp;#43;ticket&amp;#43;from&amp;#43;Linear&amp;#43;%28or&amp;#43;Jira%2C&amp;#43;or&amp;#43;GitHub&amp;#43;Issues%29.&amp;#43;Ask&amp;#43;me&amp;#43;for&amp;#43;the&amp;#43;ticket&amp;#43;number." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Implement a Linear ticket end-to-end&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="5-audit-and-tighten-over-privileged-iam-roles"&gt;5. Audit and tighten over-privileged IAM roles&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Neo audits each role against what your stack code actually does, and proposes scoped policies that improve your security posture.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;IAM cleanup is the kind of work nobody has the time to prioritize. Production has 40 roles. Half of them started with &lt;code&gt;s3:*&lt;/code&gt; because nobody had time to scope them, and the cleanup slips quarter to quarter.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Audit IAM permissions across my accounts and propose narrower policies for over-privileged stack-managed roles.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo cross-references each role&amp;rsquo;s policy against what the stack code actually calls, and opens a PR per role. The PR body lists the API calls Neo found in the stack code, like &lt;code&gt;s3:GetObject&lt;/code&gt; on &lt;code&gt;audit-logs-*&lt;/code&gt; and &lt;code&gt;s3:PutObject&lt;/code&gt; on &lt;code&gt;audit-logs-staging&lt;/code&gt;, as the justification for the scoped policy. The evidence sits next to the diff.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re unclear about which roles count as in-scope or what your team considers over-privileged, start in &lt;a href="https://www.pulumi.com/blog/neo-plan-mode/"&gt;plan mode&lt;/a&gt; and agree on that with Neo first.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Neo auditing IAM and proposing narrower policies"
autoplay muted playsinline
loop &gt;
&lt;source src="iam-narrow.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Neo auditing an over-privileged IAM role and proposing a narrower policy, with the actually-used permissions as evidence.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Audit&amp;#43;IAM&amp;#43;permissions&amp;#43;across&amp;#43;my&amp;#43;accounts&amp;#43;and&amp;#43;propose&amp;#43;narrower&amp;#43;policies&amp;#43;for&amp;#43;over-privileged&amp;#43;stack-managed&amp;#43;roles." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Audit IAM and tighten over-privileged roles&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="6-migrate-from-aws-cdk-onto-your-platforms-golden-paths"&gt;6. Migrate from AWS CDK onto your platform&amp;rsquo;s golden paths&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Neo reads your existing AWS CDK app and lands a PR that swaps AWS&amp;rsquo;s defaults for your team&amp;rsquo;s published components.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;CDK&amp;rsquo;s L2 constructs encode AWS&amp;rsquo;s defaults. &lt;code&gt;s3.Bucket&lt;/code&gt; with &lt;code&gt;encryption: BucketEncryption.S3_MANAGED&lt;/code&gt; is a sane choice, but it&amp;rsquo;s AWS&amp;rsquo;s idea of sane, not yours. A platform team that&amp;rsquo;s published its own components to the &lt;a href="https://www.pulumi.com/docs/idp/concepts/private-registry/"&gt;Pulumi Private Registry&lt;/a&gt; has already decided what &lt;em&gt;your&lt;/em&gt; bucket defaults look like: encryption with the right KMS key, tagging by cost center.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Migrate the &lt;code&gt;payments-vpc&lt;/code&gt; CDK stack to Pulumi using our published components.&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo reads the source CDK app and your registry side by side. It maps each CDK construct to its closest team-published equivalent, clarifying with you where the mapping is ambiguous.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Before (AWS CDK, AWS&amp;#39;s defaults)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Assets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;payments-assets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;encryption&lt;/span&gt;: &lt;span class="kt"&gt;s3.BucketEncryption.S3_MANAGED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;versioned&lt;/span&gt;: &lt;span class="kt"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// After (Pulumi, your team&amp;#39;s published component)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@payments/platform&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;assets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;payments-assets&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;classification&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;internal&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=I%27d&amp;#43;like&amp;#43;to&amp;#43;migrate&amp;#43;this&amp;#43;CDK&amp;#43;stack&amp;#43;to&amp;#43;Pulumi.&amp;#43;Use&amp;#43;our&amp;#43;published&amp;#43;components&amp;#43;where&amp;#43;you&amp;#43;can." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Migrate CDK onto your golden paths&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;p&gt;Neo handles &lt;a href="https://www.pulumi.com/blog/neo-migration/"&gt;Terraform and Azure ARM migrations&lt;/a&gt; the same way.&lt;/p&gt;
&lt;h2 id="7-containerize-a-service-and-migrate-it-to-kubernetes-from-a-runbook"&gt;7. Containerize a service and migrate it to Kubernetes from a runbook&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Write the containerization pattern down once. Every service after that is a prompt away.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Containerizing an application and moving it to Kubernetes involves several small decisions: which Docker image, what labels go on deployments, how ingress is wired, and how secrets reach the pod. But after a team has moved two or three services, the pattern is set. The decisions get written down in a runbook, and every subsequent migration is mostly the same shape.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Containerize the &lt;code&gt;billing-api&lt;/code&gt; service and write its Kubernetes manifests, following our K8s migration runbook in Confluence.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo reads the source repo and the runbook in Confluence via the &lt;a href="https://www.pulumi.com/blog/neo-integration-catalog/"&gt;integration catalog&lt;/a&gt; and starts working on your request.&lt;/p&gt;
&lt;p&gt;You can save this as a Neo skill that splits the work into multiple PRs — Dockerfile first, ECR config next, Deployment/Service/Ingress manifests after — and link back to each runbook convention for ease of review. The output reflects your conventions: the labels you actually use, the ingress class you&amp;rsquo;ve standardized on, and the External Secrets Operator config your team prefers.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re still the one reviewing the PRs and deciding what the cutover looks like in production. Neo follows your internal standards, so the new service ends up shaped like the last one you migrated.&lt;/p&gt;
&lt;p&gt;&lt;img src="neo-migration-prs.png" alt="Five GitHub PRs in a row, one per migration step (Dockerfile, Deployment, Service+Ingress, ExternalSecret, HPA+PDB), each citing the runbook section it implements"&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Neo migrating a VM-based service to Kubernetes step by step, following the team's Confluence runbook.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;p&gt;Once you&amp;rsquo;ve delegated something a few times, the next move is to automate it. The remaining three tasks are the kind Neo doesn&amp;rsquo;t need to be asked for. Drift, deps, compliance: they&amp;rsquo;re the operations you put on a schedule via &lt;a href="https://www.pulumi.com/blog/neo-automations/"&gt;Neo Automations&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="8-schedule-daily-configuration-drift-detection-across-your-cloud-infrastructure"&gt;8. Schedule daily configuration drift detection across your cloud infrastructure&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Schedule a daily drift check across your cloud. Wake up to PRs that fix what changed overnight.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Configuration drift is an ongoing challenge. The security team rotated an IAM role at 04:47 UTC. Someone changed a security group in the AWS console three weeks ago. Left alone, drift turns into security gaps, into compliance issues, and into the kind of &amp;ldquo;wait, who changed that?&amp;rdquo; confusion nobody wants to chase down.&lt;/p&gt;
&lt;p&gt;Pulumi Cloud is already good at configuration drift detection. Neo takes it a step further.&lt;/p&gt;
&lt;p&gt;Ask Neo:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every morning at 6 AM, check all production infrastructure for drift and create PRs to fix any issues you find.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;From then on, the task runs on its own, and you wake up to a PR per drifted resource. The description spells out what happened (&lt;code&gt;iam_role.audit-reader&lt;/code&gt; had inline policy &lt;code&gt;AllowReadAuditLogs&lt;/code&gt; added at 04:47 UTC) and cites the section of &lt;code&gt;infra/runbooks/drift.md&lt;/code&gt; Neo followed.&lt;/p&gt;
&lt;p&gt;Some drift gets encoded into the Pulumi program, like the IAM rotation above. Some gets reverted, like the security group rule added from the console. Some gets ignored entirely, like autoscaler-managed Lambda concurrency reservations the runbook tells Neo to skip. You write the runbook once; Neo follows it every morning to decide what to do.&lt;/p&gt;
&lt;p&gt;&lt;img src="neo-drift-pr.png" alt="Neo&amp;rsquo;s morning drift PR: encodes a security-team IAM rotation into the prod-audit stack, citing the runbook section that says to accept and encode the change"&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Neo's morning drift PR. The body names the resource, the change, when it happened, and the section of the runbook Neo followed to decide what to do.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Every&amp;#43;morning&amp;#43;at&amp;#43;6&amp;#43;AM%2C&amp;#43;check&amp;#43;all&amp;#43;production&amp;#43;infrastructure&amp;#43;for&amp;#43;drift&amp;#43;and&amp;#43;create&amp;#43;PRs&amp;#43;to&amp;#43;fix&amp;#43;any&amp;#43;issues&amp;#43;you&amp;#43;find." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Schedule a daily drift check&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="9-schedule-weekly-upgrades-for-outdated-lambda-runtimes-and-providers"&gt;9. Schedule weekly upgrades for outdated Lambda runtimes and providers&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Lambda runtimes and container base images age out. Schedule the upgrade pass; review the PRs Neo opens.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;AWS Lambda end-of-life notices come out months ahead. Node 20 stopped receiving updates as an AWS Lambda runtime at the end of April. Python 3.9 reached end-of-support last December. After the deadline, AWS blocks new deploys and eventually stops invoking the function. Each one needs to move to a supported runtime before the cutoff.&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Schedule it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every Sunday night at 10 PM, check our Lambda functions for runtimes nearing end-of-support and open PRs to upgrade them.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo reads the AWS Lambda runtime deprecation page, matches the end-of-support runtimes against every Lambda function in your stacks, and opens one PR per stack.&lt;/p&gt;
&lt;p&gt;If Python 3.9 is reaching end-of-support, the upgrade is to Python 3.12, and &lt;code&gt;datetime.utcnow()&lt;/code&gt; calls need to move to &lt;code&gt;datetime.now(datetime.UTC)&lt;/code&gt;. Neo can make all of those replacements in the same PR.&lt;/p&gt;
&lt;p&gt;The same task can catch container base images with critical CVEs and bump them too.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Setting up a weekly scheduled task in Neo"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-schedule-setup.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
Setting up a weekly task in the Scheduled Tasks UI. Once saved, Neo runs the prompt every Sunday night and opens PRs you review on Monday.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Every&amp;#43;Sunday&amp;#43;night&amp;#43;at&amp;#43;10&amp;#43;PM%2C&amp;#43;check&amp;#43;our&amp;#43;Lambda&amp;#43;functions&amp;#43;for&amp;#43;runtimes&amp;#43;nearing&amp;#43;end-of-support&amp;#43;and&amp;#43;open&amp;#43;PRs&amp;#43;to&amp;#43;upgrade&amp;#43;them." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Schedule a weekly runtime upgrade check&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="10-fix-aws-cis-benchmark-failures-with-daily-prs"&gt;10. Fix AWS CIS Benchmark failures with daily PRs&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Run the AWS CIS Benchmark on a schedule. Wake up to PRs that fix every failure.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://docs.aws.amazon.com/securityhub/latest/userguide/cis-aws-foundations-benchmark.html"&gt;CIS AWS Foundations Benchmark&lt;/a&gt;, available through AWS Security Hub, is something every team should be keeping an eye on. The benchmark finds issues like S3 buckets that allow public read access (&lt;code&gt;S3.1&lt;/code&gt;), root user access keys that shouldn&amp;rsquo;t exist (&lt;code&gt;IAM.4&lt;/code&gt;), or CloudTrail not being enabled (&lt;code&gt;CloudTrail.1&lt;/code&gt;). Scanning for these issues is a solved problem, but closing and addressing them is not. They pile up between audits because each one is a code change in a different stack, and nobody owns the cross-stack cleanup.&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Schedule the cleanup:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every morning, read CIS Benchmark failures from Security Hub. For every failure on an IaC-managed resource, open a PR with the fix.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Neo opens one PR per failure. A bucket failing &lt;code&gt;S3.1&lt;/code&gt; arrives as a Pulumi diff that adds &lt;code&gt;blockPublicAccess&lt;/code&gt; to the bucket in your &lt;code&gt;prod-checkout&lt;/code&gt; stack. The PR body lists the CIS rule number, the resource ID, the diff, and a clean &lt;code&gt;pulumi preview&lt;/code&gt; against the live infrastructure.&lt;/p&gt;
&lt;p&gt;The runbook is where your security team writes down what each control means for your stacks. Block public S3 buckets, except the ones tagged &lt;code&gt;public-content=true&lt;/code&gt; for CloudFront origins. Don&amp;rsquo;t auto-touch the break-glass IAM roles; page a human instead. Multi-region CloudTrail stays on, no exceptions. Neo reads that file, checks each Security Hub finding against it, and only opens a PR for the ones you&amp;rsquo;ve said are safe to fix. The rest get routed or ignored, the way your team already handles them.&lt;/p&gt;
&lt;p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Scrolling through Neo&amp;#39;s morning CIS Benchmark PR"
autoplay muted playsinline
loop &gt;
&lt;source src="neo-cis-pr.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;figcaption&gt;
&lt;center&gt;
&lt;i&gt;
A PR raised by Neo to fix a CIS Benchmark failure, with the failing rule, the resource, and the runbook decision laid out in the body.
&lt;/i&gt;
&lt;/center&gt;
&lt;/figcaption&gt;
&lt;/p&gt;
&lt;a href="https://app.pulumi.com/neo?prompt=Every&amp;#43;morning%2C&amp;#43;verify&amp;#43;all&amp;#43;resources&amp;#43;meet&amp;#43;our&amp;#43;compliance&amp;#43;policies&amp;#43;and&amp;#43;create&amp;#43;PRs&amp;#43;to&amp;#43;fix&amp;#43;violations." class="neo-card"&gt;
&lt;div class="neo-card-content"&gt;
&lt;div class="neo-card-icon"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular" fill="currentColor" role="img" aria-label="Pulumi Neo AI icon"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#c-pulumi-neo-regular"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;div class="neo-card-text"&gt;
&lt;span class="neo-card-subtitle"&gt;Start a Neo task&lt;/span&gt;
&lt;span class="neo-card-title"&gt;Schedule daily AWS CIS Benchmark scans&lt;/span&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="neo-card-arrow"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--bold" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-caret-right-bold"/&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;/a&gt;
&lt;h2 id="neo-your-newest-platform-engineer"&gt;Neo: your newest platform engineer&lt;/h2&gt;
&lt;p&gt;Over the past year, many product teams have stopped treating AI as a request-by-request assistant and started delegating to it outright.&lt;sup id="fnref:4"&gt;&lt;a href="#fn:4" class="footnote-ref" role="doc-noteref"&gt;4&lt;/a&gt;&lt;/sup&gt; Agents open pull requests, investigate issues, and iterate on review feedback.&lt;/p&gt;
&lt;p&gt;But platform engineers have held back because a bad infrastructure change doesn&amp;rsquo;t just fail, it can take production down. Coding agents benefit from fast, forgiving feedback loops, but infrastructure recovery is rarely as simple as reverting a commit.&lt;/p&gt;
&lt;p&gt;What was missing wasn&amp;rsquo;t the appetite. It was an agent with enough organizational context and &lt;a href="https://www.pulumi.com/blog/grounded-ai-why-neo-knows-your-infrastructure/"&gt;grounding&lt;/a&gt; to plan reliably, enough guardrails to feel safe and contain mistakes, and enough discipline to keep working without being asked.&lt;/p&gt;
&lt;p&gt;The theme across these tasks is clear. A thing platform engineers used to keep in their heads becomes a task you delegate, then becomes work that runs without you. Neo isn&amp;rsquo;t generating infrastructure from a template. It&amp;rsquo;s a teammate who knows your code, your providers, your conventions, your production metrics, and can raise PRs for you to review.&lt;/p&gt;
&lt;p&gt;Neo now lives in your terminal, in your pull requests, in your Slack workspace, and in Pulumi Cloud. Pick one of these workflows and &lt;a href="https://www.pulumi.com/docs/ai/neo/"&gt;give it a try&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnotes" role="doc-endnotes"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;The observant reader will notice Terraform-to-Pulumi was covered &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;in the original post&lt;/a&gt;.&amp;#160;&lt;a href="#fnref:1" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Also covered in the &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;original post&lt;/a&gt;. Last year you could ask Neo to do it once. This year you can put it on a schedule.&amp;#160;&lt;a href="#fnref:2" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Also covered in the &lt;a href="https://www.pulumi.com/blog/10-things-you-can-do-with-neo/"&gt;original post&lt;/a&gt;. Last year Neo could remediate violations on demand. This year Security Hub feeds findings to a scheduled task that knows your runbook&amp;rsquo;s interpretation of each control.&amp;#160;&lt;a href="#fnref:3" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;For a concrete example, see &lt;a href="https://www.pulumi.com/blog/seven-rules-ai-native-software-factory/"&gt;Seven Rules for Building an AI-Native Software Factory&lt;/a&gt;: Ewan Dawson, CTO of Compostable AI, runs nineteen client deployments with five engineers, using Pulumi Neo to handle most of the infrastructure work.&amp;#160;&lt;a href="#fnref:4" class="footnote-backref" role="doc-backlink"&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><author>Adam Gordon Bell</author><category>ai</category><category>platform-engineering</category><category>pulumi-neo</category><category>aws</category></item><item><title>Better CLI Interactions for Agents and Humans</title><link>https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/</link><pubDate>Tue, 19 May 2026 04:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/better-cli-interactions-for-agents-and-humans/index.png" /&gt;
&lt;p&gt;AI agents do a lot of their work through CLIs. They&amp;rsquo;re easier to call than HTTP APIs and they produce predictable output. Over the last few months our own CLI traffic has shifted from mostly people typing commands to people and agents running commands together, often in the same session.&lt;/p&gt;
&lt;p&gt;Today we&amp;rsquo;re shipping a release built for both. The &lt;a href="https://www.pulumi.com/docs/iac/cli/"&gt;Pulumi CLI&lt;/a&gt; is reorganized around three ideas: the right command should be the one you can guess, anything you can do in &lt;a href="https://www.pulumi.com/product/"&gt;Pulumi Cloud&lt;/a&gt; should also be doable from the terminal, and what comes back should be just as readable to an agent as it is to a person.&lt;/p&gt;
&lt;h2 id="designing-for-guessability"&gt;Designing for guessability&lt;/h2&gt;
&lt;p&gt;The bar we set was that both developers and coding agents should be able to guess at the right command for a particular task: &lt;code&gt;pulumi env edit&lt;/code&gt; to modify an environment, &lt;code&gt;pulumi stack get&lt;/code&gt; to see what&amp;rsquo;s going on with a stack, &lt;code&gt;pulumi org member list&lt;/code&gt; to see who&amp;rsquo;s on the team. If we had to explain which command did what, the usability bar hadn&amp;rsquo;t been met.&lt;/p&gt;
&lt;p&gt;Branches in the tree are now singular nouns like &lt;code&gt;stack&lt;/code&gt;, &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;org&lt;/code&gt;, and &lt;code&gt;deployment&lt;/code&gt;. Leaves are now verbs from a canonical vocabulary — &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt; — and they mean the same thing wherever they&amp;rsquo;re used. &lt;code&gt;edit&lt;/code&gt; always means &lt;em&gt;modify an existing thing&lt;/em&gt;. Wherever the old vocabulary differed, though, the old name still works: &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, and &lt;code&gt;open&lt;/code&gt; are all aliased to preserve backward compatibility.&lt;/p&gt;
&lt;p&gt;For the most part, product names have also been replaced with familiar nouns. Users (human or otherwise) don&amp;rsquo;t think in product names; they think in terms of resources, stacks, environments. For example, take &lt;a href="https://www.pulumi.com/esc/"&gt;Pulumi ESC&lt;/a&gt;: the product may be named ESC (and for a while the command was too), but nobody thinks &lt;em&gt;I need to initialize a new ESC&lt;/em&gt; — they think &lt;em&gt;I need to create a new environment&lt;/em&gt;. The command is therefore &lt;code&gt;pulumi env new&lt;/code&gt;, with &lt;code&gt;esc init&lt;/code&gt; preserved as an alias to avoid disrupting anyone&amp;rsquo;s existing workflows.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi env new my-project my-env
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Environment created.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="all-of-pulumi-cloud-in-the-terminal"&gt;All of Pulumi Cloud in the terminal&lt;/h2&gt;
&lt;p&gt;Up to now, most of what you could do with Pulumi Cloud had to be done either in the browser or through direct API calls. Things like reviewing deployments, setting up webhooks, finding non-compliant resources, or managing deployment settings all required you to break out &lt;code&gt;curl&lt;/code&gt; and hit the API docs or open a browser and navigate the Pulumi Cloud console.&lt;/p&gt;
&lt;p&gt;That changes today. Pulumi Cloud is now fully accessible from the command line through the &lt;code&gt;pulumi&lt;/code&gt; CLI, with consistently named nouns and verbs aligned to what you&amp;rsquo;d expect:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;pulumi stack get&lt;/code&gt; returns a complete stack overview, metadata, resource list, and more:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi stack get &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack cnunciato/chris.nunciato.org/production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output json &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s2"&gt;&amp;#34;.resources[].type&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep &lt;span class="s2"&gt;&amp;#34;aws:s3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3:BucketEventSubscription
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucket:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucket:Bucket
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketWebsiteConfiguration:BucketWebsiteConfiguration
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketOwnershipControls:BucketOwnershipControls
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aws:s3/bucketNotification:BucketNotification
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&amp;hellip; with other stack-related commands like &lt;code&gt;pulumi stack history get events&lt;/code&gt;, &lt;code&gt;pulumi stack drift list&lt;/code&gt;, &lt;code&gt;pulumi stack schedule new&lt;/code&gt;, and &lt;code&gt;pulumi stack webhook new&lt;/code&gt; alongside it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Organizational commands like &lt;code&gt;pulumi org member list&lt;/code&gt;, &lt;code&gt;pulumi org role list&lt;/code&gt;, &lt;code&gt;pulumi org usage get&lt;/code&gt;, and &lt;code&gt;pulumi org audit-log export&lt;/code&gt; can help you dig into the details when you need to as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deployment-related commands like &lt;code&gt;pulumi deployment list&lt;/code&gt;, &lt;code&gt;get&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, and &lt;code&gt;cancel&lt;/code&gt; let you see what&amp;rsquo;s running, dive into what happened, and take action without having to leave the terminal.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi deployment list &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack cnunciato/chris.nunciato.org/production &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output table
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────┬───────────┬─────────┬───────────┬──────────────┬─────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ID │ OPERATION │ VERSION │ STATUS │ INITIATED BY │ MODIFIED │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────┼───────────┼─────────┼───────────┼──────────────┼─────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 83e44b8c-643c-4e9f-9f36-0c6a81d9db2e │ update │ &lt;span class="m"&gt;140&lt;/span&gt; │ running │ cnunciato │ 2026-05-17 21:26:37.340 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 52a37cbe-b7fd-4027-8e0f-7b4785ab12e8 │ update │ &lt;span class="m"&gt;139&lt;/span&gt; │ succeeded │ cnunciato │ 2026-05-16 23:36:07.999 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ 94e04525-b3a4-42b5-9987-e344018a3324 │ preview │ &lt;span class="m"&gt;138&lt;/span&gt; │ succeeded │ cnunciato │ 2026-05-16 23:29:19.709 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────┴───────────┴─────────┴───────────┴──────────────┴─────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;And when you need to query across managed (and even unmanaged) resources, &lt;code&gt;pulumi insights resource search&lt;/code&gt; and &lt;code&gt;get&lt;/code&gt; can help you find what you&amp;rsquo;re looking for quickly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi insights resource search &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --query &lt;span class="s1"&gt;&amp;#39;type:aws:s3/bucket:Bucket org:cnunciato project:photomap stack:dev&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output table
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌──────────────────────────────────────────────────────────────────────────┬──────────────────────┬───────┬──────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ URN │ TYPE │ STACK │ MODIFIED │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├──────────────────────────────────────────────────────────────────────────┼──────────────────────┼───────┼──────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ urn:pulumi:dev::photomap::aws:apigateway:x:API&lt;span class="nv"&gt;$aws&lt;/span&gt;:s3/bucket:Bucket::api │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ urn:pulumi:dev::photomap::aws:s3/bucket:Bucket::images │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└──────────────────────────────────────────────────────────────────────────┴──────────────────────┴───────┴──────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Showing &lt;span class="m"&gt;2&lt;/span&gt; of &lt;span class="m"&gt;2&lt;/span&gt; resources.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Flags and output formats are consistent across commands (&lt;code&gt;--output table&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt;), as are the shapes of cross-cutting features like webhooks. If you&amp;rsquo;ve used &lt;code&gt;pulumi stack webhook&lt;/code&gt;, for example, you already know how to use &lt;code&gt;pulumi env webhook&lt;/code&gt; and &lt;code&gt;pulumi org webhook&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;h2 id="direct-access-to-the-pulumi-cloud-api"&gt;Direct access to the Pulumi Cloud API&lt;/h2&gt;
&lt;p&gt;For any features of Pulumi Cloud that don&amp;rsquo;t yet have their own commands, you&amp;rsquo;ve also got &lt;a href="https://www.pulumi.com/docs/iac/cli/api/"&gt;&lt;code&gt;pulumi api&lt;/code&gt;&lt;/a&gt;. It&amp;rsquo;s a &lt;code&gt;gh api&lt;/code&gt;-inspired command designed to give you direct access to the full REST API, without having to manage separate access tokens, auth settings, or request/response payloads. Everything is handled for you through your authenticated &lt;code&gt;pulumi&lt;/code&gt; CLI.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s even &lt;code&gt;pulumi api list&lt;/code&gt;, which enumerates every single endpoint that&amp;rsquo;s exposed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api list
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌───────────────┬────────┬───────────────────────────────────────┬──────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ TAG │ METHOD │ PATH │ SUMMARY │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├───────────────┼────────┼───────────────────────────────────────┼──────────────────────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ GET │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens │ ListOrgTokens │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ POST │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens │ CreateOrgToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ DELETE │ /api/orgs/&lt;span class="o"&gt;{&lt;/span&gt;orgName&lt;span class="o"&gt;}&lt;/span&gt;/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt; │ DeleteOrgToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ GET │ /api/user/tokens │ ListPersonalTokens │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ POST │ /api/user/tokens │ CreatePersonalToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ AccessTokens │ DELETE │ /api/user/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt; │ DeletePersonalToken │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="m"&gt;537&lt;/span&gt; operations. Pass --output&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="k"&gt;for&lt;/span&gt; a stable, scriptable contract.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To get the details about a particular API, use &lt;code&gt;pulumi api describe&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api describe &lt;span class="s1"&gt;&amp;#39;DELETE /api/user/tokens/{tokenId}&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# or DeletePersonalToken&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DELETE /api/user/tokens/&lt;span class="o"&gt;{&lt;/span&gt;tokenId&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Tag: AccessTokens
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Operation: DeletePersonalToken
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DeletePersonalToken
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Permanently deletes a personal access token by its identifier. The token is immediately
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;invalidated and can no longer be used &lt;span class="k"&gt;for&lt;/span&gt; authentication. Returns &lt;span class="m"&gt;204&lt;/span&gt; on success or &lt;span class="m"&gt;404&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; the token does not exist.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Parameters:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;[&lt;/span&gt;path&lt;span class="o"&gt;]&lt;/span&gt; tokenId* &lt;span class="o"&gt;(&lt;/span&gt;string&lt;span class="o"&gt;)&lt;/span&gt; — The access token identifier
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;All requests are made through your authenticated &lt;code&gt;pulumi&lt;/code&gt; CLI:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi login
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Logged in to pulumi.com as cnunciato.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi whoami
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cnunciato
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api /api/user/tokens/2cf15c7d-afad-458f-ace0-fc7ff0512b10 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --method DELETE &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Token deleted.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Token deleted.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Newly published endpoints are available through &lt;code&gt;pulumi api&lt;/code&gt; immediately, so you don&amp;rsquo;t have to wait for a new CLI release before you can start using them. See the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;Pulumi Cloud REST API documentation&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;h2 id="finding-templates-in-the-pulumi-cloud-registry"&gt;Finding templates in the Pulumi Cloud Registry&lt;/h2&gt;
&lt;p&gt;Finding out which templates are available to you through your Pulumi organization used to mean having to navigate to the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Cloud Registry&lt;/a&gt; and start searching. The new &lt;code&gt;pulumi template&lt;/code&gt; commands make this easier by letting you ask for what&amp;rsquo;s available right from the shell, either by fetching the full list or filtering with the &lt;code&gt;--name&lt;/code&gt; or &lt;code&gt;--search&lt;/code&gt; params:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi template list --search &lt;span class="s2"&gt;&amp;#34;container typescript&amp;#34;&lt;/span&gt; --org cnunciato
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;┌─────────────────────────────────────────────┬────────┬────────────┬────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ Name │ Source │ Language │ Visibility │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─────────────────────────────────────────────┼────────┼────────────┼────────────┤
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-aws-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-azure-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ pulumi/templates/container-gcp-typescript │ github │ typescript │ public │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─────────────────────────────────────────────┴────────┴────────────┴────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is especially useful when you&amp;rsquo;re working with an agent because it helps the agent discover your org&amp;rsquo;s approved templates without having to name them. Start with a prompt that tells the agent what you want to build, and let the agent find the right template for you.&lt;/p&gt;
&lt;h2 id="agent-friendly-markdown-docs-for-providers-and-components"&gt;Agent-friendly Markdown docs for providers and components&lt;/h2&gt;
&lt;p&gt;Both humans and agents need to be able to understand what&amp;rsquo;s inside a Pulumi package before they can use it. And while the &lt;a href="https://www.pulumi.com/registry/"&gt;Registry&lt;/a&gt; is an excellent resource for that, it was mainly designed to deliver HTML — a human-friendly format that agents can certainly use, but that&amp;rsquo;s much more verbose than they actually need.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;pulumi api&lt;/code&gt;, agents can fetch the details about a package from the Registry directly and get back those details either in &lt;code&gt;markdown&lt;/code&gt; or &lt;code&gt;json&lt;/code&gt;, whichever works best, filtering on properties like language where applicable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api &lt;span class="s2"&gt;&amp;#34;/api/registry/packages/pulumi/pulumi/random/versions/4.19.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;random&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;publisher&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;publisherDisplayName&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;Pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;pulumi&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;4.19.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;A Pulumi package to safely use randomness in Pulumi programs.&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;repoUrl&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;https://github.com/pulumi/pulumi-random&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi api &lt;span class="s2"&gt;&amp;#34;/api/registry/packages/pulumi/pulumi/random/versions/4.19.1/docs/random%3Aindex%2FrandomPassword%3ARandomPassword&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --output markdown
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# RandomPassword&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;resource &lt;span class="sb"&gt;`&lt;/span&gt;random:index/randomPassword:RandomPassword&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;## Example Usage&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;package main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Resources are individually addressable using their URL-encoded Pulumi type tokens — e.g., &lt;code&gt;random:index/randomPassword:RandomPassword&lt;/code&gt; — and API endpoints are configured to deliver Markdown when agents ask for it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ curl &lt;span class="s2"&gt;&amp;#34;https://api.pulumi.com/api/registry/packages/pulumi/pulumi/random/versions/latest/readme?lang=python&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Accept: text/markdown&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Installation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;The Random provider is available as a package in all Pulumi languages:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Even compared to JSON (which is itself a significant improvement over HTML), Markdown is a much more token-efficient format for agents to work with:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;JSON&lt;/th&gt;
&lt;th&gt;Markdown&lt;/th&gt;
&lt;th&gt;Tokens saved&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;random&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/readme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10.68 KB&lt;/td&gt;
&lt;td&gt;6.04 KB&lt;/td&gt;
&lt;td&gt;43%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/readme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;4.22 KB&lt;/td&gt;
&lt;td&gt;2.54 KB&lt;/td&gt;
&lt;td&gt;40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/nav?depth=full&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;204 KB&lt;/td&gt;
&lt;td&gt;170 KB&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{resource type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;15.24 KB&lt;/td&gt;
&lt;td&gt;11.28 KB&lt;/td&gt;
&lt;td&gt;26%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;azure-native&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{resource type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;48.13 KB&lt;/td&gt;
&lt;td&gt;30.37 KB&lt;/td&gt;
&lt;td&gt;37%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;aws&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/docs/{function type token}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2.40 KB&lt;/td&gt;
&lt;td&gt;1.46 KB&lt;/td&gt;
&lt;td&gt;39%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Learn more about our Registry endpoints in the &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/registry-preview/"&gt;REST API docs&lt;/a&gt;. (Or just ask your agent!)&lt;/p&gt;
&lt;h2 id="new-to-the-cli-pulumi-neo"&gt;New to the CLI: Pulumi Neo&lt;/h2&gt;
&lt;p&gt;When we launched &lt;a href="https://www.pulumi.com/neo/"&gt;Pulumi Neo&lt;/a&gt; last year, the only way to use it was in the Pulumi Cloud Console. But while there&amp;rsquo;s a ton you can do with Neo in the browser, if you&amp;rsquo;re an engineer already living in the terminal, chances are that eventually you&amp;rsquo;re going to wish you had Neo right in the CLI along with you.&lt;/p&gt;
&lt;p&gt;Now you do. Running &lt;code&gt;pulumi neo&lt;/code&gt; with or without a prompt launches a Pulumi Cloud-connected session that gives Neo access to your local environment just like any other coding agent. Use it on its own to scaffold a new project, understand an existing codebase, or debug a failing deployment — or pull it into an active session with the coding agent you&amp;rsquo;re already using. Either way, it stays in the shell you&amp;rsquo;re already working in.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll cover Neo in the CLI in more detail &lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;later this week&lt;/a&gt;. In the meantime, here&amp;rsquo;s a peek:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/neo-cli.png" alt="Running Neo in the Pulumi CLI"&gt;&lt;/p&gt;
&lt;h2 id="smaller-changes-that-add-up"&gt;Smaller changes that add up&lt;/h2&gt;
&lt;p&gt;A long list of smaller changes also runs through this release:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The core loop now speaks JSON end to end, with &lt;code&gt;pulumi up&lt;/code&gt;, &lt;code&gt;pulumi destroy&lt;/code&gt;, and &lt;code&gt;pulumi import&lt;/code&gt; all emitting structured JSON output when called with &lt;code&gt;--output json&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Streams now behave the way scripts expect them to, with data on stdout, progress and diagnostics on stderr.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Exit codes are more consistent across the board. Every failure mode — auth, resource, policy, missing stack, cancellation, timeout, and others — has its own exit code, so agents can branch on the actual cause instead of having to interpret output. The &lt;a href="https://www.pulumi.com/docs/iac/cli/exit-codes/"&gt;full table&lt;/a&gt; is in the docs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Help text explains &lt;em&gt;why&lt;/em&gt; a command exists, not just what it does, and includes at least one concrete example. Examples in &lt;code&gt;--help&lt;/code&gt; are one of the most effective ways to improve LLM accuracy on first-try invocations — and it turns out they&amp;rsquo;re pretty handy for humans, too.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="a-sneak-peek-at-a-new-command"&gt;A sneak peek at a new command&lt;/h2&gt;
&lt;p&gt;Later this week, you&amp;rsquo;ll get a closer look at &lt;code&gt;pulumi do&lt;/code&gt;, a new top-level command that enables direct resource operations like create, read, update, delete, and list across every Pulumi-supported cloud provider and resource, all in one command. A simple example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$ pulumi &lt;span class="k"&gt;do&lt;/span&gt; aws getAvailabilityZones
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;groupNames&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2-zg-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;names&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2a&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2b&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2c&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;us-west-2d&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;region&amp;#34;&lt;/span&gt;: &lt;span class="s2"&gt;&amp;#34;us-west-2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;zoneIds&amp;#34;&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az2&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az3&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;usw2-az4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It might look like that&amp;rsquo;s calling the AWS CLI, but it&amp;rsquo;s not — it&amp;rsquo;s using &lt;a href="https://www.pulumi.com/registry/packages/aws/api-docs/getavailabilityzones/"&gt;the same AWS provider function&lt;/a&gt; a full Pulumi program would use, only without the program, and invoked directly from the CLI.&lt;/p&gt;
&lt;p&gt;More on how it works, and what you can do with it, in the days ahead.&lt;/p&gt;
&lt;h2 id="try-it-yourself"&gt;Try it yourself&lt;/h2&gt;
&lt;p&gt;A lot of what makes a developer tool worth using is in the details, and most of what&amp;rsquo;s in &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;this release&lt;/a&gt; is exactly that, across the whole CLI, with humans and agents in mind.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love for you to &lt;a href="https://www.pulumi.com/docs/install/"&gt;grab the latest release&lt;/a&gt; and give it a try. Tell us what&amp;rsquo;s now easy, what&amp;rsquo;s still hard, and what to fix next on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt; or in the &lt;a href="https://slack.pulumi.com/"&gt;community Slack&lt;/a&gt;. The fastest way the CLI gets better is feedback from the humans and agents who live in it.&lt;/p&gt;</description><author>Michael Fallihee</author><author>Christian Nunciato</author><category>features</category><category>pulumi-cli</category><category>ai-agents</category><category>product-launches</category></item><item><title>The Agentic Infrastructure Era</title><link>https://www.pulumi.com/blog/the-agentic-infrastructure-era/</link><pubDate>Tue, 19 May 2026 03:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/the-agentic-infrastructure-era/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/the-agentic-infrastructure-era/index.png" /&gt;
&lt;p&gt;The first frontier agents excelled at was coding. The reason is evident: we have billions of lines of self-documenting code available on the internet for the LLMs to learn from. We can measure their performance on coding thanks to linters, type checkers, compilers, and test suites. The most advanced agentic systems to hit product/market fit have been coding-oriented, and it has resulted in an intense velocity increase in how much and how fast code we can write.&lt;/p&gt;
&lt;p&gt;But as the AI tsunami whips up reams of code, what happens to it becomes just as critical. As an industry, we&amp;rsquo;ve moved beyond just coding to engineering, which includes documentation, tests, automation, and, yes, managing the very infrastructure our applications need to run. The deeper into production you go, however, the less good agents naturally are at helping. At Pulumi, we live and breathe infrastructure, and have seen this firsthand. But we&amp;rsquo;ve also been hard at work building the platform this new era runs on. In this post, I&amp;rsquo;ll share our point of view, what we&amp;rsquo;ve built, what we&amp;rsquo;re launching today, and why all infrastructure is about to be agentic.&lt;/p&gt;
&lt;p&gt;New to the term? Start with &lt;a href="https://www.pulumi.com/what-is/what-is-agentic-infrastructure/"&gt;what agentic infrastructure is&lt;/a&gt; and how it works.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;See Pulumi Neo in action →&lt;/a&gt; Neo is the agent at the center of everything below: it previews changes, checks them against policy, and opens PRs for your review.&lt;/p&gt;
&lt;h2 id="llms-are-natural-coders"&gt;LLMs are natural coders&lt;/h2&gt;
&lt;p&gt;It is remarkable to look back and note that frontier models, less than two years ago, in August 2024, scored just 33% on SWE-bench Verified. Present-day models score 86%, which represents a 4x reduction in the errors models will make when coding. This enables models to solve increasingly difficult coding problems, and humans can lean more heavily on them to offload tasks. Anthropic&amp;rsquo;s new Mythos model scores 94% and, although it isn&amp;rsquo;t generally available at the time of this article, there&amp;rsquo;s no question we&amp;rsquo;ll close in on 95% by the end of 2026. That is another 2.3x reduction in error rates. This very naturally puts us onto the last mile of fully agentic coding.&lt;/p&gt;
&lt;p&gt;This has been the result of code being highly in-distribution combined with the relentless pursuit of solving coding problems from the frontier labs, especially with Anthropic&amp;rsquo;s Claude Code, but now with OpenAI&amp;rsquo;s Codex, driving a tight feedback loop that turns into an improvement flywheel.&lt;/p&gt;
&lt;p&gt;Given that LLMs are natural coders, most of us simply assumed that the breakout success we&amp;rsquo;ve seen with agents for coding would automatically translate into new problem domains. And for sure, we have seen some success. But perhaps not as much as we&amp;rsquo;d like. Not all problem domains are documented equally well so that the models can naturally learn about them.&lt;/p&gt;
&lt;p&gt;Andrej Karpathy noted nearly a year ago that, &amp;ldquo;Building a modern app is a bit like assembling IKEA furniture,&amp;rdquo; observing that, though writing the code was easy, fun, and fast, the next mile of actually getting the application running in production entailed many things the LLM wasn&amp;rsquo;t naturally good at, including &amp;ldquo;services, API keys, configurations, dev/prod deployments.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;At the same time, we&amp;rsquo;re seeing something magical happen here at Pulumi: LLMs are now doing over 20% of the infrastructure deployments, up from virtually zero a year ago. We expect this to grow to over 50% before the end of this year and well beyond afterwards.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.pulumi.com/blog/the-agentic-infrastructure-era/agentic-share-circular-light.png" alt="Over 20% of all Pulumi operations are now being handled by LLMs."&gt;&lt;/p&gt;
&lt;p&gt;The agentic infrastructure era is here. Today we&amp;rsquo;re announcing several new platform capabilities to accelerate it further.&lt;/p&gt;
&lt;p&gt;Before getting to what&amp;rsquo;s new, however, why are we seeing this happening in reality?&lt;/p&gt;
&lt;h2 id="turning-infrastructure-problems-into-coding-problems"&gt;Turning infrastructure problems into coding problems&lt;/h2&gt;
&lt;p&gt;We began our journey with our open-source infrastructure-as-code project nearly ten years ago. Having spent much of my career working on programming languages and compilers, I had a strong conviction that the right substrate for infrastructure was the languages developers already knew and loved, not yet another DSL and certainly not piles of YAML. So we focused first on great ergonomics for humans, and for us, that meant letting you use programming languages, tools, and ecosystems that humans already know and love. Languages like Python, TypeScript, Go, .NET, Java, and more. Infrastructure as code also, importantly, comes with guardrails to make infrastructure deployments dependable, reviewable, and auditable. Over time we&amp;rsquo;ve built out an entire platform with security, compliance, and governance capabilities.&lt;/p&gt;
&lt;p&gt;One way of thinking about this is we modeled the realm of cloud infrastructure inside the realm of programming languages: cloud resources become objects, configurations are just variables, dependencies between resources are just references, standard blueprints become classes. Doing so turns the cloud into something that is suddenly programmable, and allows us to apply real software engineering patterns and practices to infrastructure.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the twist we&amp;rsquo;ve realized this past year. It is a happy accident that the combination of this plus the verifiability of every change is the exact combination that empowers agents to do infrastructure. LLMs are natural coders. By mapping infrastructure space in code space, agents can do what they&amp;rsquo;re great at – code – and the infrastructure as code engine is the link that maps those code edits back down into infrastructure space. And as the SWE-bench curve plays out, every domain expressed in code rides it. Infrastructure, thanks to the bet we made nine years ago, is now one of them.&lt;/p&gt;
&lt;p&gt;This isn&amp;rsquo;t just about volume of in-distribution code. Most production infrastructure code lives in private repositories. In contrast, public Python and TypeScript include vast amounts of genuinely production-grade open source, demonstrating real patterns at scale. Public infrastructure DSL corpora skew heavily toward tutorial-grade content that doesn&amp;rsquo;t scale. By modeling infrastructure in real languages, Pulumi inherits at-scale in-distribution directly. Patterns in Python or TypeScript generalize from what the model has practiced, while DSL patterns are idiosyncratic by definition and don&amp;rsquo;t compound the same way. Code can express everything an engineer can do, which is exactly why models trained on it have become prolific engineers.&lt;/p&gt;
&lt;p&gt;What does this look like in practice? For example, an agent can define reusable infrastructure:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_coreweave&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;coreweave&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi_nvidia_aicr&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;aicr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ComponentResource&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;A reusable training cluster resource.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;training:Cluster&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;coreweave&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KubernetesCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-k8s&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# gb200/b200/h100&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aicr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClusterStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-aicr&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kubeconfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;training&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;kubeflow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And then flexibly consume it – all using languages, like Python, it is already fluent in:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pulumi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;infra&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;orchestration&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RLFleet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Spin up an RL stack with 1 learner and 8 rollout workers.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;learner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;learner&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gb200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rollouts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TrainingCluster&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;rollout-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accelerator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;b200&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;fleet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RLFleet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ppo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;learner&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;learner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rollouts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pulumi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;login&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fleet&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Beyond just being in-distribution, infrastructure as code also gives us a critical piece: the ability to diff changes at the infrastructure layer. Just as we wouldn&amp;rsquo;t vibe code without git showing us the source changes, we shouldn&amp;rsquo;t vibe infrastructure without a tool that shows what it will do before it does it, and what it has already done in the past. It&amp;rsquo;s like git diff for your infrastructure.&lt;/p&gt;
&lt;p&gt;The combination of languages, type systems, linting, testing, and infrastructure diffs gives agents enough of what they need to create a fully closed, verifiable, self-correcting loop. Verifiability is the thing that ultimately matters. Every action an agent takes can be previewed, policy-checked, reviewed, and audited. By humans, by other agents, by CI/CD automation. Guardrails guide the agent and verifiability proves the end result.&lt;/p&gt;
&lt;p&gt;When I say &amp;ldquo;infrastructure&amp;rdquo; by the way, I mean something quite broad. It includes public cloud hyperscalers, of course, like AWS, Azure, Google Cloud, and CoreWeave. It includes cloud native technologies like Kubernetes and Helm. It also includes private clouds powered by VMware and other data center technologies. It includes broad cloud platforms like Cloudflare. But, subtly, also any hosted managed infrastructure service, such as Snowflake, MongoDB, Databricks, and more. And increasingly, the observability, security, and operational tooling that wraps everything else, like Datadog, Sentry, PagerDuty, and other systems that give agents the context to reason about what&amp;rsquo;s actually happening in production. We support thousands of providers with a consistent programming model and agents are increasingly writing those too.&lt;/p&gt;
&lt;h2 id="what-were-shipping-today"&gt;What we&amp;rsquo;re shipping today&lt;/h2&gt;
&lt;p&gt;The foundation of expressing infrastructure as code, combined with verifiable changes, makes a 100% agentic infrastructure future even conceivable. But we still have work to realize this vision.&lt;/p&gt;
&lt;h3 id="meeting-agents-where-they-work-the-cli"&gt;Meeting agents where they work (the CLI)&lt;/h3&gt;
&lt;p&gt;We know real code is the right substrate for agentic infrastructure – but we also know agents want to start with the smallest possible commitment and progressively level up. So we&amp;rsquo;ve designed the Pulumi experience as a progression: an agent should be able to sign up, run its first command, and grow into a full infrastructure as code workflow without ever hitting a wall or manual intervention. Here&amp;rsquo;s what we&amp;rsquo;re launching today to make that journey work end-to-end:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/agent-accounts/"&gt;Agent accounts&lt;/a&gt;.&lt;/strong&gt; Now agents can use free, ephemeral Pulumi Cloud accounts straight from Claude Code, Codex, OpenCode, Copilot, Cursor, and others. This lets an agent do anything a human could with the Pulumi product without a manual signup step, removing friction while letting agents benefit from robust infrastructure management. A human can claim that account at any time to make it permanent and to share with their team.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/pulumi"&gt;One-command execution&lt;/a&gt;.&lt;/strong&gt; Today an agent needs to know how to find, download, and install Pulumi, and manage subsequent versioning and upgrades. Anything that adds friction is discouraging to an agent. We now have an npm package that enables &lt;code&gt;npx pulumi &amp;lt;anything&amp;gt;&lt;/code&gt;-style commands so agents can run any Pulumi command anywhere without needing to worry about installation or version pinning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-do-direct-resource-operations/"&gt;Imperative infrastructure operations&lt;/a&gt;.&lt;/strong&gt; The new &lt;code&gt;pulumi do&lt;/code&gt; command enables direct create, read, update, delete, list, and API operations with a single command. For example, &lt;code&gt;pulumi do create eks:Cluster&lt;/code&gt; spins up an AWS EKS cluster with built-in best practices, and &lt;code&gt;pulumi do update cloudflare:r2:Bucket --tags '{ &amp;quot;Foo&amp;quot;: &amp;quot;Bar&amp;quot; }'&lt;/code&gt; updates a bucket&amp;rsquo;s tags. All thousands of providers and hundreds of thousands of resource types in the Pulumi ecosystem are supported across clouds. As the complexity of your scenario outgrows singular commands, it is easy to eject out into a full-blown infrastructure-as-code project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;Pulumi Cloud in the CLI&lt;/a&gt;.&lt;/strong&gt; Over the years, we&amp;rsquo;ve added tons of great capabilities to Pulumi Cloud – things like change history, time-to-live stacks, drift detection, resource discovery and search, private registries, IDP, audit logs, secrets management, team-wide policy enforcement – but didn&amp;rsquo;t add the respective ergonomic commands to the CLI. These are the sort of features that matter at scale. Now it&amp;rsquo;s all there in your terminal where agents can use them. Over 30 new commands, you can think of this as the equivalent of the &lt;code&gt;gh&lt;/code&gt; CLI which agents really like.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;&lt;strong&gt;Read the blog&lt;/strong&gt;: Better CLI Interactions for Agents and Humans →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="neo-everywhere-you-work"&gt;Neo, everywhere you work&lt;/h3&gt;
&lt;p&gt;Once an agent (or a team) has graduated through these capabilities, what comes next is asynchronous infrastructure work and, increasingly, autonomy. That&amp;rsquo;s where Neo comes in: Pulumi&amp;rsquo;s own infrastructure agent, now upgraded with the surfaces, integrations, and cadences teams actually need to run agentic infrastructure in production. We are shipping:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-neo-cli/"&gt;Neo in the CLI&lt;/a&gt;.&lt;/strong&gt; The new &lt;code&gt;pulumi neo&lt;/code&gt; command lets you run the same agent that is already in Pulumi Cloud. It even shares the same agentic loop and uses a sophisticated architecture where the agent workstation is your local computer, allowing it to more seamlessly access source context and tools. This allows you to do agentic infrastructure wherever you prefer: Neo in the cloud for asynchronous, autonomous tasks, or your workstation for more intensive deep-dive paired sessions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-github-slack/"&gt;Neo GitHub and Slack Apps&lt;/a&gt;.&lt;/strong&gt; Now you can @-mention Neo from GitHub pull requests, and/or straight from Slack, to kick off agentic infrastructure workflows wherever it is most convenient, complete with whatever guardrails you&amp;rsquo;ve configured already.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-integrations/"&gt;Neo Integration Catalog&lt;/a&gt;.&lt;/strong&gt; A new integration catalog lets you configure connectors to other systems that bring valuable infrastructure management context, including Atlassian, Datadog, Honeycomb, Linear, PagerDuty, and Supabase. This lets you tap into additional planning, specification, observability, and live site incident data, expanding what agents can do on Days 0, 1, and especially 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/neo-automations/"&gt;Scheduled Tasks and Read-Only Sessions&lt;/a&gt;.&lt;/strong&gt; Now you can automate recurring infrastructure tasks, including confining Neo to read-only operations for extra safety. This opens up scenarios like reporting on infrastructure patterns weekly, automatically cleaning up waste in your dev accounts daily, or scheduled maintenance and upgrades.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/blog/10-more-things-you-can-do-with-neo/"&gt;&lt;strong&gt;Read the blog&lt;/strong&gt;: 10 More Things You Can Do with Pulumi Neo →&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="partnering-with-the-frontier-of-ai-infrastructure"&gt;Partnering with the frontier of AI infrastructure&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;re investing in deep partnerships with the companies building the frontier of AI infrastructure, and are shipping two new partner providers in close collaboration with the teams behind them:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/registry/packages/coreweave/"&gt;CoreWeave provider&lt;/a&gt;.&lt;/strong&gt; This new provider brings the full power of the CoreWeave platform, the leader in GPU infrastructure, to help teams provision AI workloads with ease. This includes support for all of the CoreWeave services including CoreWeave Kubernetes Service (CKS) and includes several examples and templates out of the box for training and inference architectures written in AI-native languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/pulumi-labs/pulumi-nvidia-aicr"&gt;NVIDIA AI Cluster Runtime (AICR) provider&lt;/a&gt;.&lt;/strong&gt; This new provider delivers fully functional NVIDIA software stacks atop the underlying cloud provider&amp;rsquo;s GPU infrastructure. This packages out-of-the-box components like NVIDIA GPU Operator, Kubeflow, NIM Operator, and dozens more otherwise tricky-to-configure cluster components. We&amp;rsquo;re excited to showcase the new AICR provider in tandem with our new CoreWeave provider: you can now spin up a CKS cluster and configure it with AICR in one program.&lt;/p&gt;
&lt;h3 id="educating-and-measuring-agentic-infrastructure-intelligence"&gt;Educating and measuring agentic infrastructure intelligence&lt;/h3&gt;
&lt;p&gt;We&amp;rsquo;ve also invested in making Pulumi maximally legible to agents, because the best tools only matter if agents can find them, read them, and know which one to reach for and when:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/#agent-friendly-markdown-docs-for-providers-and-components"&gt;Agent-friendly docs&lt;/a&gt;.&lt;/strong&gt; We now serve our docs website in markdown to agents and did a pass over our documentation and CLI text to ensure it&amp;rsquo;s maximally useful to agents.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/blog/better-cli-interactions-for-agents-and-humans/"&gt;Agent-friendly CLI ergonomics&lt;/a&gt;.&lt;/strong&gt; We have added &lt;code&gt;--json&lt;/code&gt; and structured errors across the CLI to help agents parse and react to outputs appropriately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/ai/skills/"&gt;New skills&lt;/a&gt;.&lt;/strong&gt; We&amp;rsquo;ve done a pass over our skills and added a new uber-skill that describes how an agent should leverage the full suite of capabilities we now offer, from Level 0 (agent accounts), to Level 1 (&lt;code&gt;pulumi do&lt;/code&gt;), to Level 2 (full IaC and &lt;code&gt;pulumi up&lt;/code&gt;), to Level 3 (Pulumi Cloud governance and full autonomy with Neo), and beyond. It&amp;rsquo;s handy for humans too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;InfraBench.&lt;/strong&gt; We have created a new benchmark to measure how well an agent performs on a wide array of representative infrastructure tasks. This is the infrastructure equivalent to SWE-bench and lets us measure stock agents, agents plus the new tools and skills, and Neo, and how they&amp;rsquo;re improving over time. Although we are still hard at work on building out the comprehensive suite, and will keep it internally for now, we will begin publishing our progress against InfraBench as we continue tackling new problems and improving agent performance.&lt;/p&gt;
&lt;h2 id="what-comes-next"&gt;What comes next&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;re primarily focused on two pillars as we go forward:&lt;/p&gt;
&lt;p&gt;First, we are making &lt;a href="https://www.pulumi.com/what-is/what-is-agentic-infrastructure/"&gt;agentic infrastructure&lt;/a&gt; a reality with increasingly autonomous workflows. The pace and scale of infrastructure in an AI era are beyond anything we&amp;rsquo;ve seen before, and we need to ensure infrastructure doesn&amp;rsquo;t become the bottleneck to velocity. We will be shipping steady improvements that help agents score better on InfraBench as a measure of their abilities. This will begin with new building blocks and in-context improvements, but we&amp;rsquo;re really excited that every improvement the frontier labs ship in general-purpose coding ability is automatically an improvement in agentic infrastructure on Pulumi, at zero cost to us or to our users. The result is that Pulumi-equipped agents will consistently and measurably outperform raw agents on real infrastructure work, and that gap will compound as the substrate and the models both improve.&lt;/p&gt;
&lt;p&gt;Next, a world in which agents are provisioning, updating, monitoring, and managing all of our infrastructure changes the human/agent/infrastructure interface greatly. We need better change management, policy enforcement, and observability tools. Going from a single human doing a single infrastructure task at a time, to a single agent doing that task, to teams of agents doing lots of autonomous infrastructure tasks at once, will reveal new bottlenecks needed to fully govern your infrastructure. We have a lot of those facilities in Pulumi Cloud already but we will continue pushing here to improve them and ensure they scale up as fast as they need to. This is the layer that matters even as agents themselves get great at infrastructure. The smartest agent in the world still needs guardrails, audit trails, and policy enforcement to be trusted with production systems at scale, and that layer gets more valuable as agents get more capable, not less.&lt;/p&gt;
&lt;p&gt;The combination of these two things will lead to a world where agents are able to manage more infrastructure, and to do so with increasing autonomy, while human operators retain full visibility, understanding, and control over what their teams of agents are doing at all times. This is the full engineering loop applied to infrastructure. Not just code generation, but design, review, deployment, and operation, with agents and humans collaborating across every step.&lt;/p&gt;
&lt;h2 id="its-a-new-era-and-were-just-getting-started"&gt;It&amp;rsquo;s a new era, and we&amp;rsquo;re just getting started&lt;/h2&gt;
&lt;p&gt;It was remarkable to see in practice and at scale that what&amp;rsquo;s good for humans is good for agents: ergonomic infrastructure as code. We&amp;rsquo;ve seen every point along the spectrum, ranging from Wiz managing 1 million resources and doing 100k daily deployments, to Compostable.ai already living the 100% agentic infrastructure dream, to a frontier lab who grew their infrastructure footprint by 982% in a year, all using infrastructure modeled in true code. All very different scales and teams, but with one thing in common: it was code all the way down.&lt;/p&gt;
&lt;p&gt;Languages and verifiability already provide strong foundations, however, there are still clear areas we need to improve, beginning with making the full suite of infrastructure automation, security, and governance tools more accessible to agents. That&amp;rsquo;s what today is all about. To deep dive on details of &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/"&gt;the launches&lt;/a&gt;, check out the &lt;a href="https://www.pulumi.com/releases/agentic-infrastructure-era/#from-the-blog"&gt;companion blog posts&lt;/a&gt; released today.&lt;/p&gt;
&lt;p&gt;Agentic infrastructure is a super exciting one-way door for our industry. We&amp;rsquo;re pushing hard to take this beyond 20% and toward 100% in the years ahead. This is uniquely enabled by infrastructure as code in languages the models already speak combined with built-in verifiability that makes agentic work automatically safe. There&amp;rsquo;s more to be done, however, today&amp;rsquo;s launch will bend the curve even further upwards. We&amp;rsquo;re still only just getting started.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/install/"&gt;Get started with Pulumi free →&lt;/a&gt; Install the CLI and provision your first agentic-ready stack in minutes.&lt;/p&gt;
&lt;p&gt;Happy clouding,&lt;/p&gt;
&lt;p&gt;-Joe&lt;/p&gt;</description><author>Joe Duffy</author><category>announcements</category><category>ai</category><category>pulumi-neo</category><category>features</category></item><item><title>Connect Any Git or Mercurial Repo to Pulumi with Custom VCS</title><link>https://www.pulumi.com/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/</link><pubDate>Mon, 04 May 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/connect-any-git-server-to-pulumi-deployments-with-custom-vcs/index.png" /&gt;
&lt;p&gt;Custom VCS is a new Pulumi Cloud integration that connects any Git or Mercurial version control system to &lt;a href="https://www.pulumi.com/docs/deployments/concepts/"&gt;Pulumi Deployments&lt;/a&gt; using webhooks and centrally managed credentials. Pulumi Cloud already has native integrations with &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, but if your team uses a self-hosted or third-party VCS, you&amp;rsquo;ve been limited to manually configuring credentials per stack with no webhook-driven automation. Custom VCS closes that gap.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Many teams run self-hosted or third-party Git servers that Pulumi Cloud doesn&amp;rsquo;t have a native integration for, and some teams still use Mercurial. Until now, their only option was the raw git source approach: embedding credentials directly in each stack&amp;rsquo;s deployment settings, with no way to trigger deployments automatically on push, and no support for Mercurial at all.&lt;/p&gt;
&lt;p&gt;This meant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No push-to-deploy&lt;/strong&gt;: Every deployment had to be triggered manually or through a separate CI pipeline.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scattered credentials&lt;/strong&gt;: Each stack configured its own credentials independently, with no centralized management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No org-level integration&lt;/strong&gt;: There was no shared configuration that multiple stacks could reference.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-custom-vcs-works"&gt;How Custom VCS works&lt;/h2&gt;
&lt;p&gt;Custom VCS integrations introduce an org-level integration type that works with any Git or Mercurial server. The setup has three parts:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Credentials through ESC&lt;/strong&gt;: Instead of OAuth flows, you store your VCS credentials (a personal access token, SSH key, or username/password) in a &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt; environment. The same credential structure works for both Git and Mercurial. The integration references this environment by name and resolves credentials at deployment time. Multiple stacks can share the same credentials without duplicating secrets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Manual repository registration&lt;/strong&gt;: You add repositories to the integration by name. Pulumi joins the repository name with the integration&amp;rsquo;s base URL to form clone URLs. There&amp;rsquo;s no auto-discovery, so you control exactly which repositories are available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Webhook-driven deployments&lt;/strong&gt;: Pulumi provides a webhook endpoint and an HMAC shared secret. You configure your VCS server to POST a JSON payload on push events, and Pulumi automatically triggers deployments for matching stacks. The webhook supports branch filtering and optional path filtering.&lt;/p&gt;
&lt;h2 id="whats-supported"&gt;What&amp;rsquo;s supported&lt;/h2&gt;
&lt;p&gt;Custom VCS focuses on the deployment automation use case. Here&amp;rsquo;s how it compares to native integrations:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Native integrations&lt;/th&gt;
&lt;th&gt;Custom VCS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Push-to-deploy&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Path filtering&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR/MR previews&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit status checks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR comments&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review stacks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Features like PR comments, commit statuses, and review stacks require deep API integration with each VCS platform, so they aren&amp;rsquo;t available with Custom VCS. If your VCS provider is GitHub, GitLab, or Azure DevOps, we recommend using the native integration for the full feature set.&lt;/p&gt;
&lt;h2 id="neo-support"&gt;Neo support&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Neo&lt;/a&gt;, Pulumi&amp;rsquo;s AI assistant, works with Custom VCS integrations for repository operations that don&amp;rsquo;t depend on VCS-specific APIs. Neo can clone and push to Git and Mercurial repositories registered with your Custom VCS integration using the credentials from the integration&amp;rsquo;s ESC environment. Neo cannot open pull requests or create new repositories on Custom VCS servers at this time. Those operations require APIs unique to each VCS platform and are only available through native integrations.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;To set up a Custom VCS integration:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt; in Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Add integration&lt;/strong&gt; and choose &lt;strong&gt;Custom VCS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Provide a name, base URL, and ESC environment containing your credentials.&lt;/li&gt;
&lt;li&gt;Add your repositories.&lt;/li&gt;
&lt;li&gt;Configure your VCS server to send webhooks to the provided URL.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For the full setup guide including webhook payload format, HMAC signing, and credential configuration, see the &lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/integrations/version-control/custom-vcs/"&gt;Custom VCS documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/concepts/"&gt;Pulumi Deployments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/concepts/triggers/#push-to-deploy"&gt;Push-to-deploy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Michael Fallihee</author><category>features</category><category>pulumi-cloud</category></item><item><title>Policy Packs Can Now Access Pulumi ESC Environments</title><link>https://www.pulumi.com/blog/policy-packs-can-now-access-pulumi-esc-environments/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/policy-packs-can-now-access-pulumi-esc-environments/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/policy-packs-can-now-access-pulumi-esc-environments/index.png" /&gt;
&lt;p&gt;Policy authors who need external credentials or environment-specific configuration have had to hardcode values or manage them outside of Pulumi. Policy packs can now reference &lt;a href="https://www.pulumi.com/product/secrets-management/"&gt;Pulumi ESC&lt;/a&gt; environments, bringing centralized secrets and configuration management to your policies.&lt;/p&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Pulumi &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/"&gt;policy packs&lt;/a&gt; let you enforce rules across your infrastructure, but some policies need more than just the resource inputs they evaluate. A policy that validates resources against an external compliance API needs an API token. A cost-enforcement policy might need different spending thresholds for development and production environments. An access-control policy might need to reference an internal service registry.&lt;/p&gt;
&lt;p&gt;Until now, these values had to be hardcoded in your policy group configuration or managed through a separate process entirely. This created several problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Security risk&lt;/strong&gt;: Credentials stored in plain text in policy group config&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational burden&lt;/strong&gt;: Updating a credential meant touching every policy group that used it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No environment separation&lt;/strong&gt;: The same values applied everywhere, with no way to vary configuration across environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;Policy packs can now reference ESC environments, just like &lt;a href="https://www.pulumi.com/docs/esc/concepts/outputs/"&gt;stacks already do&lt;/a&gt;. When you attach an ESC environment to a policy pack in a policy group, the values from that environment are available to your policies at runtime — whether you&amp;rsquo;re running preventative or audit policies.&lt;/p&gt;
&lt;p&gt;This means your policy packs can use ESC for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Secrets&lt;/strong&gt;: API tokens, service credentials, and other sensitive values managed through ESC&amp;rsquo;s secrets management, including dynamic credentials from providers like AWS, Azure, and GCP&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: Environment-specific thresholds, allowed regions, service allowlists, and other policy parameters that vary across environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="policy-esc-screenshot.png" alt="Configuring ESC environments on a policy pack in the Pulumi Cloud console"&gt;&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;You configure ESC environment references on a policy pack within a policy group. At runtime, the values from those environments are resolved and made available to your policies through the policy pack&amp;rsquo;s configuration.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example ESC environment that provides configuration to a compliance policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;compliance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;xxxxxxxxxxxxxxxx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;costThreshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;policyConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cost-compliance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;maxMonthlyCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${compliance.costThreshold}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiEndpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;https://compliance.example.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${compliance.apiToken}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/esc/concepts/outputs/"&gt;&lt;code&gt;policyConfig&lt;/code&gt;&lt;/a&gt; property works just like &lt;a href="https://www.pulumi.com/docs/esc/concepts/outputs/"&gt;&lt;code&gt;pulumiConfig&lt;/code&gt;&lt;/a&gt; does for stacks. Values nested under each policy name are made available as configuration to that policy at runtime. Secrets remain encrypted and are only decrypted when the environment is resolved.&lt;/p&gt;
&lt;p&gt;You can also use the &lt;code&gt;environmentVariables&lt;/code&gt; property to inject values as environment variables into the policy runtime, following the same pattern as &lt;a href="https://www.pulumi.com/docs/esc/concepts/outputs/"&gt;stack environment variables&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="example-compliance-api-validation"&gt;Example: compliance API validation&lt;/h2&gt;
&lt;p&gt;Consider a policy that validates every new resource against an external compliance API before it can be provisioned. The API requires an authentication token and returns whether the resource configuration meets your organization&amp;rsquo;s compliance standards.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;, the API token lived in the policy group configuration in plain text. Rotating the token meant updating every policy group. There was no audit trail for who accessed the credential, and no way to use different API endpoints for staging and production compliance checks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt;, the API token lives in an ESC environment. You get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized rotation&lt;/strong&gt;: Update the token in one place and every policy group that references the environment picks up the change&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Access controls&lt;/strong&gt;: ESC&amp;rsquo;s role-based access controls govern who can view or modify the credential&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Audit trail&lt;/strong&gt;: Every access to the environment is logged&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Environment separation&lt;/strong&gt;: Use different ESC environments for different policy groups, so staging policies validate against a staging compliance endpoint while production policies use the production endpoint&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;To start using ESC environments with your policy packs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/concepts/environments/"&gt;Create an ESC environment&lt;/a&gt; with your policy configuration and secrets&lt;/li&gt;
&lt;li&gt;Attach the environment to a policy pack in your policy group through the Pulumi Cloud console&lt;/li&gt;
&lt;li&gt;Update your policies to read from the configuration values provided by the environment&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To learn more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/concepts/outputs/"&gt;&lt;code&gt;policyConfig&lt;/code&gt; reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/"&gt;Policy packs documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/esc/get-started/"&gt;Get started with Pulumi ESC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Dan Biwer</author><category>esc</category><category>policy-as-code</category><category>features</category></item><item><title>Pulumi Cloud REST API Docs, Now Generated from OpenAPI</title><link>https://www.pulumi.com/blog/rest-api-docs-from-openapi/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/rest-api-docs-from-openapi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/rest-api-docs-from-openapi/index.png" /&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;Pulumi Cloud REST API reference&lt;/a&gt; is now generated directly from the live &lt;a href="https://api.pulumi.com/api/openapi/pulumi-spec.json"&gt;OpenAPI spec&lt;/a&gt; at build time. Every endpoint, parameter, request body, and response schema you see on the page comes from the same spec the API itself publishes. The docs now stay in sync with the API automatically!&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;The previous REST API reference was a set of handwritten pages. That meant every new endpoint, renamed parameter, or revised response shape needed a matching docs PR, and in practice the pages drifted. Small inconsistencies added up: missing parameters, outdated request shapes, schemas that no longer matched what the API returned. We wanted a durable fix that keeps the docs in sync as the API grows.&lt;/p&gt;
&lt;p&gt;Generating the reference from the OpenAPI spec closes that gap. When the API ships a change, the docs pick it up automatically the next time our docs are built.&lt;/p&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new&lt;/h2&gt;
&lt;p&gt;The reference at &lt;code&gt;/docs/reference/cloud-rest-api/&lt;/code&gt; now includes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find what you need faster
&lt;ul&gt;
&lt;li&gt;Endpoints are grouped by product area — Stacks, Deployments, Environments, Organizations, Registry, Insights, AI, Workflows, and more — so you can jump straight to the part of the API you&amp;rsquo;re working with.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Complete request and response details
&lt;ul&gt;
&lt;li&gt;Every endpoint documents its parameters, request body, and the exact shape of what it returns, so you know what to send and what to expect back without guessing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;One-click navigation between related types
&lt;ul&gt;
&lt;li&gt;When a response references another object, the type name is a link. Click through to drill into its full definition if desired instead of scrolling a lengthy API reference page.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-this-unlocks-for-agents"&gt;What this unlocks for agents&lt;/h2&gt;
&lt;p&gt;Keeping the reference in sync with the spec isn&amp;rsquo;t just a human convenience. It changes what&amp;rsquo;s reliable for AI agents that read the docs and call the API on your behalf. An agent reading a handwritten reference might see a parameter that was renamed six months ago, or miss a field the API now returns, and the call fails silently or in ways that are hard to debug. When the reference is generated from the spec, the agent is working from what the API actually accepts today.&lt;/p&gt;
&lt;p&gt;Say you&amp;rsquo;re onboarding a new team and need to stand up their access in Pulumi Cloud. Point an agent at the REST API reference and ask it to create an &lt;code&gt;sre-oncall&lt;/code&gt; team, add four members, and grant admin on three stacks. The agent walks the teams, memberships, and stack-permissions endpoints, builds the right sequence of calls, and executes.&lt;/p&gt;
&lt;p&gt;The same pattern holds for bulk audits and cleanup. Ask an agent to find every stack in your org with no recent updates and tag them &lt;code&gt;stale&lt;/code&gt;, and it can paginate correctly because the response schema matches reality. While workflows like these were technically possible before, they&amp;rsquo;re much more reliable now.&lt;/p&gt;
&lt;h2 id="same-url-existing-links-keep-working"&gt;Same URL, existing links keep working&lt;/h2&gt;
&lt;p&gt;The generated docs live at the same URL as the previous reference: &lt;code&gt;/docs/reference/cloud-rest-api/&lt;/code&gt;. Bookmarks, blog links, and inbound search traffic still land on the right page. Redirects are in place for any API reference docs page that has been tweaked, renamed, or moved.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Start at the new &lt;a href="https://www.pulumi.com/docs/reference/cloud-rest-api/"&gt;REST API reference&lt;/a&gt; and browse by category. Each page links through to the request and response object schemas it uses.&lt;/p&gt;
&lt;p&gt;If you spot anything that looks wrong, the most likely culprit is the OpenAPI spec itself — file an issue in &lt;a href="https://github.com/pulumi/docs"&gt;pulumi/docs&lt;/a&gt; and we&amp;rsquo;ll trace it back to the source. For tag intros and structural improvements, PRs to &lt;a href="https://github.com/pulumi/docs"&gt;pulumi/docs&lt;/a&gt; are welcome. Questions and feedback are always welcome in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/reference/cloud-rest-api/"
class="btn btn-primary"
&gt;
Explore the REST API
&lt;/a&gt;</description><author>Devon Grove</author><category>pulumi-cloud</category><category>features</category><category>api</category></item><item><title>Bitbucket Cloud Meets Pulumi Cloud</title><link>https://www.pulumi.com/blog/bitbucket-vcs-integration/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/bitbucket-vcs-integration/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/bitbucket-vcs-integration/index.png" /&gt;
&lt;p&gt;Pulumi Cloud now supports Bitbucket Cloud as a first-class VCS integration, joining &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;. Connect your Bitbucket workspace to deploy infrastructure on every push, preview changes on pull requests, spin up ephemeral review stacks, and get AI-powered change summaries — all without an external CI/CD pipeline.&lt;/p&gt;
&lt;h2 id="deploy-infrastructure-from-bitbucket"&gt;Deploy infrastructure from Bitbucket&lt;/h2&gt;
&lt;p&gt;Connect a Bitbucket repository to a stack and infrastructure deploys automatically when you push to your configured branch. Configure path filters so only relevant file changes trigger deployments, and manage environment variables and secrets directly in Pulumi Cloud. No external CI/CD pipeline required.&lt;/p&gt;
&lt;p&gt;Every pull request gets an infrastructure preview showing exactly what will change before merging. &lt;a href="https://www.pulumi.com/product/neo/"&gt;Neo&lt;/a&gt; posts AI-generated summaries explaining what the changes mean in plain language, so reviewers can understand the impact without reading resource diffs.&lt;/p&gt;
&lt;h2 id="two-ways-to-connect"&gt;Two ways to connect&lt;/h2&gt;
&lt;p&gt;The integration supports two authentication methods depending on your Bitbucket plan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Personal OAuth&lt;/strong&gt; works with every workspace, including free plans. Authorize through the standard OAuth flow and you&amp;rsquo;re connected.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Workspace tokens&lt;/strong&gt; are available for Premium workspaces. Generate a token with the required scopes (&lt;code&gt;repository:admin&lt;/code&gt;, &lt;code&gt;repository:write&lt;/code&gt;, &lt;code&gt;pullrequest:write&lt;/code&gt;, &lt;code&gt;webhook&lt;/code&gt;) and paste it into Pulumi Cloud for a service-account-style connection that isn&amp;rsquo;t tied to an individual user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both methods register webhooks automatically — no manual configuration required.&lt;/p&gt;
&lt;h2 id="scaffold-new-projects-from-your-repositories"&gt;Scaffold new projects from your repositories&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/docs/idp/concepts/new-project-wizard/"&gt;new project wizard&lt;/a&gt; discovers your Bitbucket workspace, repositories, and branches so you can scaffold and deploy a new stack without leaving Pulumi Cloud. Create a new repository directly from the wizard or select an existing one and configure VCS-backed deployments in a few clicks.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;An org admin configures the integration under &lt;strong&gt;Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Authorize with Bitbucket using personal OAuth or a workspace token.&lt;/li&gt;
&lt;li&gt;Deploy infrastructure with first-class workflows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For full setup details, see the &lt;a href="https://www.pulumi.com/docs/integrations/version-control/bitbucket/"&gt;Bitbucket integration docs&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://app.pulumi.com/signin"
class="btn btn-primary"
target="_blank"
rel="noopener noreferrer"
&gt;
Connect your Bitbucket workspace
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular text-sm ml-2" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-arrow-square-out-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;</description><author>Luke Ward</author><category>bitbucket</category><category>features</category><category>pulumi-cloud</category></item><item><title>Scan AWS GovCloud and more partitions with Pulumi Insights</title><link>https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/</link><pubDate>Tue, 14 Apr 2026 09:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/scan-aws-govcloud-china-with-pulumi-insights/index.png" /&gt;
&lt;p&gt;Pulumi Insights account scanning now supports every AWS partition. If your workloads run in GovCloud, China, the European Sovereign Cloud, or one of the ISO intelligence-community clouds, you can get the same resource discovery, cross-account search, and AI-assisted insights that commercial accounts already have.&lt;/p&gt;
&lt;h2 id="supported-partitions"&gt;Supported partitions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;AWS Standard (Commercial)&lt;/li&gt;
&lt;li&gt;AWS GovCloud (US)&lt;/li&gt;
&lt;li&gt;AWS ISO (US)&lt;/li&gt;
&lt;li&gt;AWS ISOB (US)&lt;/li&gt;
&lt;li&gt;AWS ISOF (US)&lt;/li&gt;
&lt;li&gt;AWS ISOE (Europe)&lt;/li&gt;
&lt;li&gt;AWS European Sovereign Cloud&lt;/li&gt;
&lt;li&gt;AWS China&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can also exclude specific regions from discovery — useful when regions are disabled by SCPs or fall outside an audit&amp;rsquo;s scope.&lt;/p&gt;
&lt;p&gt;&lt;img src="aws-partition-picker.png" alt="Choosing an AWS partition when creating an Insights account"&gt;&lt;/p&gt;
&lt;h2 id="set-it-up"&gt;Set it up&lt;/h2&gt;
&lt;p&gt;In the Pulumi Cloud console:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Accounts → Create account&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;AWS&lt;/strong&gt; as the provider.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Add your configuration&lt;/strong&gt;, pick the target partition.&lt;/li&gt;
&lt;li&gt;Supply credentials via a Pulumi ESC environment. The OIDC trust policy uses the partition-appropriate ARN prefix (&lt;code&gt;arn:aws-us-gov:&lt;/code&gt;, &lt;code&gt;arn:aws-cn:&lt;/code&gt;, etc.).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For IAM and ESC setup, see the &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/accounts/"&gt;Insights accounts docs&lt;/a&gt;. Log in to &lt;a href="https://app.pulumi.com/"&gt;Pulumi Cloud&lt;/a&gt; to get started.&lt;/p&gt;</description><author>Alejandro Cotroneo</author><category>insights</category><category>aws</category><category>features</category><category>cloud-engineering</category></item><item><title>Introducing Bun as a Runtime for Pulumi</title><link>https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/</link><pubDate>Wed, 08 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/introducing-bun-as-a-runtime-for-pulumi/index.png" /&gt;
&lt;p&gt;Last year we added support for &lt;a href="https://www.pulumi.com/blog/bun-package-manager/"&gt;Bun as a package manager&lt;/a&gt; for Pulumi TypeScript projects. Today we&amp;rsquo;re taking the next step: Bun is now a fully supported runtime for Pulumi programs. Set &lt;code&gt;runtime: bun&lt;/code&gt; in your &lt;code&gt;Pulumi.yaml&lt;/code&gt; and Bun will execute your entire Pulumi program, with no Node.js required. Since Bun&amp;rsquo;s 1.0 release, this has been one of our &lt;a href="https://github.com/pulumi/pulumi/issues/13904"&gt;most requested features&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="why-bun"&gt;Why Bun?&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://bun.sh/"&gt;Bun&lt;/a&gt; is a JavaScript runtime designed as an all-in-one toolkit: runtime, package manager, bundler, and test runner. For Pulumi users, the most relevant advantages are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Native TypeScript support&lt;/strong&gt;: Bun runs TypeScript directly without requiring &lt;a href="https://typestrong.org/ts-node/"&gt;ts-node&lt;/a&gt; or a separate compile step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast package management&lt;/strong&gt;: Bun&amp;rsquo;s built-in package manager can install dependencies significantly faster than npm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node.js compatibility&lt;/strong&gt;: Bun &lt;a href="https://bun.sh/docs/runtime/nodejs-apis"&gt;aims for 100% Node.js compatibility&lt;/a&gt;, so the npm packages you already use with Pulumi should work out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With &lt;code&gt;runtime: bun&lt;/code&gt;, Pulumi uses Bun for both running your program and managing your packages, giving you a streamlined single-tool experience.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;To create a new Pulumi project with the Bun runtime, run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi new bun
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This creates a TypeScript project configured to use Bun. The generated &lt;code&gt;Pulumi.yaml&lt;/code&gt; looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-bun-project&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;bun&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From here, write your Pulumi program as usual. For example, to create a random password using the &lt;code&gt;@pulumi/random&lt;/code&gt; package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bun add @pulumi/random
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;random&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/random&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;RandomPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;password&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;length&lt;/span&gt;: &lt;span class="kt"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then deploy with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Prerequisites:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bun.sh/docs/installation"&gt;Bun&lt;/a&gt; 1.3 or later&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/install/"&gt;Pulumi&lt;/a&gt; 3.227.0 or later&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="converting-existing-nodejs-projects"&gt;Converting existing Node.js projects&lt;/h2&gt;
&lt;p&gt;If you have an existing Pulumi TypeScript project running on Node.js, you can convert it to use the Bun runtime in a few steps.&lt;/p&gt;
&lt;h3 id="1-update-pulumiyaml"&gt;1. Update &lt;code&gt;Pulumi.yaml&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Change the &lt;code&gt;runtime&lt;/code&gt; field from &lt;code&gt;nodejs&lt;/code&gt; to &lt;code&gt;bun&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;Before:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;nodejs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;packagemanager&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;npm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;bun&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;When the runtime is set to &lt;code&gt;bun&lt;/code&gt;, Bun is also used as the package manager — there&amp;rsquo;s no need to configure a separate &lt;code&gt;packagemanager&lt;/code&gt; option.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-update-tsconfigjson"&gt;2. Update &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Bun handles TypeScript differently from Node.js with &lt;code&gt;ts-node&lt;/code&gt;. Update your &lt;code&gt;tsconfig.json&lt;/code&gt; to use &lt;a href="https://bun.sh/docs/typescript#suggested-compileroptions"&gt;Bun&amp;rsquo;s recommended compiler options&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;compilerOptions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;lib&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ESNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;target&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;ESNext&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Preserve&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;moduleDetection&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;force&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;moduleResolution&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bundler&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;allowJs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;allowImportingTsExtensions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;verbatimModuleSyntax&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;strict&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;skipLibCheck&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noFallthroughCasesInSwitch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noUncheckedIndexedAccess&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;noImplicitOverride&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key differences from a typical Node.js &lt;code&gt;tsconfig.json&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/tsconfig/#module"&gt;&lt;code&gt;module: &amp;quot;Preserve&amp;quot;&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#moduleresolution-bundler"&gt;&lt;code&gt;moduleResolution: &amp;quot;bundler&amp;quot;&lt;/code&gt;&lt;/a&gt;: Let Bun handle module resolution instead of compiling to CommonJS. The &lt;code&gt;bundler&lt;/code&gt; resolution strategy allows extensionless imports while still respecting &lt;code&gt;package.json&lt;/code&gt; exports, matching how Bun resolves modules in practice.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax"&gt;&lt;code&gt;verbatimModuleSyntax: true&lt;/code&gt;&lt;/a&gt;: Enforces consistent use of ESM &lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; syntax. TypeScript will flag any remaining CommonJS patterns like &lt;code&gt;require()&lt;/code&gt; at compile time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-switch-to-esm"&gt;3. Switch to ESM&lt;/h3&gt;
&lt;p&gt;Bun makes it easy to go full ESM and it&amp;rsquo;s the &lt;a href="https://bun.sh/docs/runtime/module-resolution"&gt;recommended module format&lt;/a&gt; for Bun projects. Add &lt;code&gt;&amp;quot;type&amp;quot;: &amp;quot;module&amp;quot;&lt;/code&gt; to your &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;module&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules"&gt;ECMAScript module (ESM)&lt;/a&gt; syntax, one thing that gets easier is working with async code. In a CommonJS Pulumi program, if you need to await a data source or other async call before declaring resources, the program must be wrapped in an &lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/javascript/#enabling-async-support"&gt;async entrypoint function&lt;/a&gt;. With ESM and Bun, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await"&gt;top-level await&lt;/a&gt; just works, so you can skip the wrapper function entirely and &lt;code&gt;await&lt;/code&gt; directly at the module level:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kr"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;@pulumi/aws&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;azs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getAvailabilityZones&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;available&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;az&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`my-bucket-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;az&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucketNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If your existing program does use an async entrypoint with &lt;code&gt;export =&lt;/code&gt;, just replace it with the ESM-standard &lt;code&gt;export default&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// CommonJS (Node.js default)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-bucket&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;: &lt;span class="kt"&gt;bucket.id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ESM (used with Bun)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kr"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BucketV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-bucket&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;bucketName&lt;/span&gt;: &lt;span class="kt"&gt;bucket.id&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="4-update-the-pulumi-sdk"&gt;4. Update the Pulumi SDK&lt;/h3&gt;
&lt;p&gt;Make sure you&amp;rsquo;re running &lt;code&gt;@pulumi/pulumi&lt;/code&gt; version 3.226.0 or later:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bun add @pulumi/pulumi@latest
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="5-install-dependencies-and-deploy"&gt;5. Install dependencies and deploy&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi install
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="bun-as-runtime-vs-bun-as-package-manager"&gt;Bun as runtime vs. Bun as package manager&lt;/h2&gt;
&lt;p&gt;With this release, there are now two ways to use Bun with Pulumi:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Bun&amp;rsquo;s role&lt;/th&gt;
&lt;th&gt;Node.js required?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;runtime: bun&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs your program and manages packages&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;runtime: { name: nodejs, options: { packagemanager: bun } }&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Manages packages only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use &lt;code&gt;runtime: bun&lt;/code&gt; for the full Bun experience. The package-manager-only mode is still available for projects that need Node.js-specific features like function serialization.&lt;/p&gt;
&lt;h2 id="known-limitations"&gt;Known limitations&lt;/h2&gt;
&lt;p&gt;The following Pulumi features are not currently supported when using the Bun runtime:&lt;/p&gt;
&lt;div class="note note-warning"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-warning-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/iac/guides/clouds/aws/lambda/"&gt;Callback functions (magic lambdas)&lt;/a&gt;&lt;/strong&gt; are not supported. APIs like &lt;code&gt;aws.lambda.CallbackFunction&lt;/code&gt; and event handler shortcuts (e.g., &lt;code&gt;bucket.onObjectCreated&lt;/code&gt;) use &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/"&gt;function serialization&lt;/a&gt; which requires Node.js &lt;code&gt;v8&lt;/code&gt; and &lt;code&gt;inspector&lt;/code&gt; modules that are only partially supported in Bun.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.pulumi.com/docs/iac/concepts/providers/dynamic-providers/"&gt;Dynamic providers&lt;/a&gt;&lt;/strong&gt; are not supported. Dynamic providers (&lt;code&gt;pulumi.dynamic.Resource&lt;/code&gt;) similarly rely on &lt;a href="https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/"&gt;function serialization&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If your project uses any of these features, continue using &lt;code&gt;runtime: nodejs&lt;/code&gt;. You can still benefit from Bun&amp;rsquo;s fast package management by setting &lt;code&gt;packagemanager: bun&lt;/code&gt; in your runtime options.&lt;/p&gt;
&lt;h2 id="start-using-bun-with-pulumi"&gt;Start using Bun with Pulumi&lt;/h2&gt;
&lt;p&gt;Bun runtime support is available now in &lt;a href="https://www.pulumi.com/docs/install/"&gt;Pulumi 3.227.0&lt;/a&gt;. To get started:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new project: &lt;code&gt;pulumi new bun&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Read the docs: &lt;a href="https://www.pulumi.com/docs/iac/languages-sdks/javascript/"&gt;TypeScript (Node.js) SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Report issues or share feedback on &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub&lt;/a&gt; or in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you to everyone who upvoted, commented on, and contributed to &lt;a href="https://github.com/pulumi/pulumi/issues/13904"&gt;the original feature request&lt;/a&gt;. Your feedback helped shape this feature, and we&amp;rsquo;d love to hear how it works for you.&lt;/p&gt;</description><author>Julien Poissonnier</author><category>features</category><category>typescript</category><category>bun</category></item><item><title>Automate Azure App Secret Rotation with ESC</title><link>https://www.pulumi.com/blog/automate-azure-app-secret-rotation-with-esc/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/automate-azure-app-secret-rotation-with-esc/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/automate-azure-app-secret-rotation-with-esc/index.png" /&gt;
&lt;p&gt;&lt;a href="https://learn.microsoft.com/en-us/entra/fundamentals/whatis"&gt;Microsoft Entra ID&lt;/a&gt; (formerly Azure Active Directory) is Azure&amp;rsquo;s identity and access management service. Any time your application needs to authenticate with Entra ID, you create an &lt;strong&gt;app registration&lt;/strong&gt; and give it a &lt;a href="https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-credentials?tabs=client-secret"&gt;client secret&lt;/a&gt; that proves its identity. But those secrets expire, and if you don&amp;rsquo;t rotate them in time, your app loses access.&lt;/p&gt;
&lt;p&gt;If you or your team manages Azure app registrations, you know that keeping track of client secrets is a constant hassle. Forgetting to rotate them before they expire can lead to broken authentication and unexpected outages. With &lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC&lt;/a&gt;&amp;rsquo;s &lt;code&gt;azure-app-secret&lt;/code&gt; rotator, you can automate client secret rotation for your Azure apps, so you never have to worry about expired credentials again.&lt;/p&gt;
&lt;h2 id="setup"&gt;Setup&lt;/h2&gt;
&lt;h3 id="prerequisites"&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;An Azure App Registration&lt;/li&gt;
&lt;li&gt;An &lt;a href="https://www.pulumi.com/docs/esc/providers/login/azure-login/"&gt;azure-login&lt;/a&gt; environment
&lt;ul&gt;
&lt;li&gt;Note for OIDC users: Since Azure does not support wildcard subject matches, you will need to add a &lt;a href="https://www.pulumi.com/docs/esc/guides/configuring-oidc/azure/#add-federated-credentials"&gt;federated credential&lt;/a&gt; for the azure-login environment as well as each environment that imports it.&lt;/li&gt;
&lt;li&gt;The Azure identity used for rotation must have the &lt;code&gt;Application.ReadWrite.All&lt;/code&gt; Graph API permission, or the identity must be added as an Owner of the specific app registration whose secrets will be rotated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s assume your azure-login environment looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# my-org/logins/production&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;azure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::open::azure-login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;your-client-id&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tenantId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;your-tenant-id&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;subscriptionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;your-subscription-id&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;oidc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a new environment for your rotator. If you have the existing credentials, set them in the &lt;a href="https://www.pulumi.com/docs/esc/concepts/builtin-functions/fn-rotate/#parameters"&gt;state&lt;/a&gt; object so the rotator will treat them as the &lt;code&gt;current&lt;/code&gt; credentials.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# my-org/rotators/secret-rotator&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::rotate::azure-app-secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;login&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;${environments.logins.production.azure.login}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;target-app-client-id&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;lifetimeInDays&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# How long each new secret is valid (max 730 days)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;current&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;secret-id&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;&amp;lt;secret-value&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;lifetimeInDays&lt;/code&gt; field controls how long each generated secret remains valid before it expires. Azure allows a maximum of 730 days (two years), but shorter lifetimes are recommended for better security. Make sure to set a rotation &lt;a href="https://www.pulumi.com/docs/esc/concepts/rotators/#schedule"&gt;schedule&lt;/a&gt; that runs before the lifetime expires so your credentials are always fresh.&lt;/p&gt;
&lt;p&gt;Azure app registrations can have at most two client secrets at any given time, so the rotator maintains a &lt;code&gt;current&lt;/code&gt; and &lt;code&gt;previous&lt;/code&gt; secret. When a rotation occurs, the existing &lt;code&gt;current&lt;/code&gt; secret becomes the &lt;code&gt;previous&lt;/code&gt; secret, and a new secret is created to take its place as the new &lt;code&gt;current&lt;/code&gt;. This ensures a smooth rollover with no downtime, since the previous secret remains valid until the next rotation.&lt;/p&gt;
&lt;p&gt;Once this is set up, you&amp;rsquo;re ready to go! You never need to worry about your client secrets expiring, and you will always have the latest credentials in your ESC Environment.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn::rotate::azure-app-secret&lt;/code&gt; rotator is available now in all Pulumi ESC environments. For more information, check out the &lt;a href="https://www.pulumi.com/docs/esc/providers/rotators/azure-app-secret/"&gt;fn::rotate::azure-app-secret documentation&lt;/a&gt;!&lt;/p&gt;</description><author>Sean Yeh</author><category>esc</category><category>azure</category></item><item><title>Introducing the pulumi policy analyze Command for Existing Stacks</title><link>https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-policy-analyze-existing-stacks/index.png" /&gt;
&lt;p&gt;You can now run &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/"&gt;policy packs&lt;/a&gt; against your existing stack state without running your Pulumi program or making provider calls. The new &lt;code&gt;pulumi policy analyze&lt;/code&gt; command evaluates your current infrastructure against local policy packs directly, turning policy validation into a fast, repeatable check.&lt;/p&gt;
&lt;h2 id="why-this-command-matters"&gt;Why this command matters&lt;/h2&gt;
&lt;p&gt;Policy authoring and policy updates usually involve an iteration loop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Make a policy change.&lt;/li&gt;
&lt;li&gt;Run a policy check.&lt;/li&gt;
&lt;li&gt;Inspect violations or remediations.&lt;/li&gt;
&lt;li&gt;Repeat until the policy behavior matches intent.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Before this command, that loop often depended on &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_preview/"&gt;&lt;code&gt;pulumi preview&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://www.pulumi.com/docs/iac/cli/commands/pulumi_up/"&gt;&lt;code&gt;pulumi up&lt;/code&gt;&lt;/a&gt;, which can be heavier than you need when your goal is validating policy logic against known state.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;pulumi policy analyze&lt;/code&gt;, you can evaluate your current stack state directly and quickly.&lt;/p&gt;
&lt;h2 id="basic-usage"&gt;Basic usage&lt;/h2&gt;
&lt;p&gt;At minimum, provide a policy pack path and optionally a stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy analyze &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack ./policy-pack &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;You can also pass a config file for each policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy analyze &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack ./policy-pack &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --policy-pack-config ./policy-config.dev.json &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --stack dev
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If any mandatory policy violations are found, the command exits non-zero.&lt;/p&gt;
&lt;p&gt;If remediation policies fire, those changes are reported in output, but stack state is not modified.&lt;/p&gt;
&lt;h2 id="testing-new-policy-packs-as-a-developer"&gt;Testing new policy packs as a developer&lt;/h2&gt;
&lt;p&gt;For policy pack development, this command is useful as a tight local feedback loop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pick a representative stack (&lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt;, or a fixture stack).&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi policy analyze&lt;/code&gt; against that stack after each policy change.&lt;/li&gt;
&lt;li&gt;Use the output to verify mandatory, advisory, and remediation behavior.&lt;/li&gt;
&lt;li&gt;Repeat before publishing the policy pack or attaching it to broader policy groups.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Two output modes are especially useful:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--diff&lt;/code&gt; for a concise, human-readable view while iterating locally.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--json&lt;/code&gt; for structured output that can be consumed in scripts and CI.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="using-it-in-ai-and-agent-workflows"&gt;Using it in AI and agent workflows&lt;/h2&gt;
&lt;p&gt;This command is also a good primitive for AI-assisted policy workflows.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;pulumi policy analyze&lt;/code&gt; can emit JSON and a clear process exit code, agents can use it for deterministic policy evaluation steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Propose or edit policy rules.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;pulumi policy analyze --json&lt;/code&gt; against target stacks.&lt;/li&gt;
&lt;li&gt;Parse violations and remediation signals.&lt;/li&gt;
&lt;li&gt;Suggest policy fixes, config adjustments, or targeted infrastructure changes.&lt;/li&gt;
&lt;li&gt;Re-run analysis until mandatory violations are resolved.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For example, an agent tasked with fixing a policy violation can run &lt;code&gt;pulumi policy analyze --json&lt;/code&gt; to get a structured list of violations, identify which resources are non-compliant, generate targeted infrastructure changes, then re-run analysis to confirm the violations are resolved, all without triggering a full preview on each iteration. The same loop works for policy authoring: an agent can propose a new policy rule, test it against several representative stacks, and surface unintended violations before the rule is published.&lt;/p&gt;
&lt;p&gt;This works well for automation because the command doesn&amp;rsquo;t execute your Pulumi program or make provider calls, so there are no side effects or runtime variance between runs. The JSON output and non-zero exit code on failure give agents a clear pass/fail contract to build on.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pulumi policy analyze&lt;/code&gt; is available in &lt;a href="https://github.com/pulumi/pulumi/releases/tag/v3.229.0"&gt;Pulumi v3.229.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you are authoring or tuning policy packs, start by running this command against a known stack in your environment. It is a quick way to validate policy behavior before rollout.&lt;/p&gt;
&lt;p&gt;For implementation details, see the merged PR: &lt;a href="https://github.com/pulumi/pulumi/pull/22250"&gt;pulumi/pulumi#22250&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/discovery-governance/policy/"
class="btn btn-primary"
&gt;
Get started with policy as code
&lt;/a&gt;</description><author>Fraser Waters</author><category>policy-as-code</category><category>features</category><category>infrastructure-as-code</category><category>ai</category></item><item><title>Neo Plan Mode: Iterate Before You Execute</title><link>https://www.pulumi.com/blog/neo-plan-mode/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-plan-mode/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-plan-mode/index.png" /&gt;
&lt;p&gt;Infrastructure work ranges from simple updates to complex multi-stack operations. For straightforward tasks, jumping straight to execution is often fine. But complex tasks benefit from deliberate upfront thinking: understanding what exists, identifying dependencies, and agreeing on an approach before anything changes. Today we&amp;rsquo;re launching Plan Mode, a dedicated experience for collaborating with Neo on a detailed plan before execution begins.&lt;/p&gt;
&lt;h2 id="plan-mode"&gt;Plan Mode&lt;/h2&gt;
&lt;p&gt;Without dedicated planning, Neo balances planning with progress toward execution. That works well for many tasks, but complex operations benefit from more thorough upfront discovery. Plan Mode now makes upfront deliberation a first-class workflow, where instead of focusing on getting to execution, Neo focuses entirely on discovery and synthesis until you explicitly approve the plan.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Enter Plan Mode by selecting the plan button when starting a task. Neo shifts its behavior:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Discovery&lt;/strong&gt;: Neo investigates your environment — examining existing infrastructure, reading relevant code, checking dependencies, and researching patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Synthesis&lt;/strong&gt;: From that research, Neo produces a plan explaining what it will do and why. The plan references specific things Neo discovered, like a particular stack configuration or dependency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refinement&lt;/strong&gt;: You refine the plan through normal conversation, challenging assumptions, asking for an alternative approach, or requesting more detail on a specific area.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Approval&lt;/strong&gt;: Once you&amp;rsquo;re satisfied, you approve the plan and execution begins. Neo carries forward everything it learned during discovery, so the transition from planning to execution is seamless.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="when-to-use-it"&gt;When to use it&lt;/h2&gt;
&lt;p&gt;Plan Mode is opt-in. You choose it when you want to work through an approach before committing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complex multi-stack operations&lt;/strong&gt; where understanding dependencies matters&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unfamiliar infrastructure&lt;/strong&gt; where discovery reduces churn&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autonomous execution&lt;/strong&gt; where plan approval is your key control point before Neo runs without step-by-step oversight&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Plan Mode is available now for all Pulumi Cloud organizations. It works with any &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#task-modes"&gt;task mode&lt;/a&gt;, so you can pair thorough upfront planning with whatever level of execution autonomy fits the situation.&lt;/p&gt;
&lt;p&gt;To try it, &lt;a href="https://app.pulumi.com/neo"&gt;open Neo in Pulumi Cloud&lt;/a&gt;. For more details, see the &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#plan-mode"&gt;Plan Mode documentation&lt;/a&gt;.&lt;/p&gt;</description><author>Pulumi Neo Team</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Introducing Read-Only Mode for Pulumi Neo</title><link>https://www.pulumi.com/blog/neo-read-only-mode/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/neo-read-only-mode/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/neo-read-only-mode/index.png" /&gt;
&lt;p&gt;A platform engineer with broad access might want Neo to analyze infrastructure and suggest changes, but include guarantees it won&amp;rsquo;t actually apply them. Read-only mode makes that possible: Neo does the heavy lifting and hands off a pull request for your existing deployment process to pick up.&lt;/p&gt;
&lt;h2 id="control-what-neo-can-change"&gt;Control what Neo can change&lt;/h2&gt;
&lt;p&gt;Neo runs with the permissions of the user who creates a task, but you often want a tighter boundary. Read-only mode solves this by letting you cap Neo&amp;rsquo;s permissions at task creation time. Neo can still read your infrastructure, run previews, and open pull requests, but it cannot deploy, update, or destroy resources.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you create a Neo task, you now choose between two permission levels:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;Option&lt;/th&gt;
&lt;th style="text-align: left"&gt;What Neo can do&lt;/th&gt;
&lt;th style="text-align: left"&gt;Availability&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Use my permissions&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;Full access (current default behavior)&lt;/td&gt;
&lt;td style="text-align: left"&gt;All tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;strong&gt;Read-only&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: left"&gt;Read, preview, and create PRs. No infrastructure mutations.&lt;/td&gt;
&lt;td style="text-align: left"&gt;All tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Read-only mode takes your existing permissions and removes the ability to make changes. Neo remains fully active, meaning it can still read your infrastructure state, run previews, write and refactor code, create branches, and open pull requests. If Neo encounters an operation it can&amp;rsquo;t perform in read-only mode, the operation fails and Neo reports what it would have done. The only difference is that Neo cannot trigger deployments or other write operations in Pulumi Cloud directly.&lt;/p&gt;
&lt;h2 id="read-only-mode-and-auto-approve"&gt;Read-only mode and auto-approve&lt;/h2&gt;
&lt;p&gt;Neo&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/ai/neo/tasks/#task-modes"&gt;operating modes&lt;/a&gt; let you choose how much oversight you want: review mode for full approval at each step, balanced mode for approving only mutating operations, and auto mode for hands-off execution.&lt;/p&gt;
&lt;p&gt;Read-only mode pairs well with auto-approve. Because Neo cannot perform write operations like deployments or destroys, you can let it run autonomously and trust that the output is a pull request, not a production change. Kick off a task, let Neo work in the background, and come back to a ready-to-review PR.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Read-only mode is available today for all Pulumi Cloud users.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.pulumi.com/signin"&gt;Sign in to Pulumi Cloud&lt;/a&gt; and select &lt;strong&gt;Read-only&lt;/strong&gt; when creating your next Neo task&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/ai/"&gt;Read the Neo documentation&lt;/a&gt; for detailed guides on permission levels&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.pulumi.com/"&gt;Join the Community Slack&lt;/a&gt; to share your feedback&lt;/li&gt;
&lt;/ul&gt;</description><author>Florian Stadler</author><category>pulumi-neo</category><category>ai</category><category>features</category></item><item><title>Introducing OTel Tracing in the Pulumi CLI</title><link>https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/</link><pubDate>Wed, 01 Apr 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/introducing-otel-tracing-in-the-pulumi-cli/index.png" /&gt;
&lt;p&gt;Tracing is an important part of our CLI observability story. So far we&amp;rsquo;ve relied on (the now deprecated) &lt;a href="https://opentracing.io/"&gt;OpenTracing&lt;/a&gt; for this. We have now added OTel tracing to the CLI, which is more future-proof, and should in most cases give you a better view over what the CLI is doing.&lt;/p&gt;
&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;We introduced tracing using &lt;a href="https://opentracing.io"&gt;OpenTracing&lt;/a&gt; &lt;a href="https://github.com/pulumi/pulumi/pull/521"&gt;all the way back in 2017&lt;/a&gt;, before &lt;a href="https://opentelemetry.io/"&gt;OpenTelemetry&lt;/a&gt; was a thing. This served us well over the years, but as OpenTracing was deprecated, and OTel emerged as the new and maintained thing, it got harder and harder to justify further investment in a tracing infrastructure that was deprecated. Last year we started focusing more on performance, and it became more and more clear that we&amp;rsquo;d either have to enhance our current OpenTracing setup, or do the work to switch to OTel.&lt;/p&gt;
&lt;p&gt;In the end it was a relatively easy decision to move to the more modern and fully supported OTel, especially as more and more tooling around it starts emerging.&lt;/p&gt;
&lt;h2 id="enter-otel"&gt;Enter OTel&lt;/h2&gt;
&lt;p&gt;With the decision to move to OTel made, the only thing left to decide was how to implement it. There were a couple of constraints we faced here. First, we wanted to make sure that traces are easily shareable. This means ideally a text file in whatever format, that can be shared easily. Second, pulumi&amp;rsquo;s plugin system works by spawning a new process per plugin. We want to get traces from each of these plugins to make sure we have as much coverage as possible. And third, ideally we also want to get traces from plugins that only implement OpenTracing, but not OTel yet, since someone can upgrade the CLI, but not the plugins for example.&lt;/p&gt;
&lt;p&gt;Given these constraints, we decided to implement an OTel collector in the CLI, that could then forward the traces to whatever output format we want. This means that plugins only ever need to send traces back to the CLI over &lt;a href="https://grpc.io/"&gt;gRPC&lt;/a&gt;, and the CLI will do any further processing. This means only one process will write to the file, if requested.&lt;/p&gt;
&lt;p&gt;For plugins we always request both OpenTracing and OTel traces. If both are requested and OTel is supported by the plugin, the plugin is expected to only send the OTel version of the traces. For OpenTracing traces, we collect them in the collector in the CLI, and then translate them internally to OTel traces. This way we can still get the traces from older plugins, without them needing to change anything.&lt;/p&gt;
&lt;h2 id="try-it-out"&gt;Try it out&lt;/h2&gt;
&lt;p&gt;Currently the OTel exporter supports both exporting the traces directly via gRPC to a collector, or to a file, where the traces are JSON encoded. This file can then be shared and imported into a trace viewer at a later time. To do this, you can use the &lt;code&gt;--otel-traces &amp;lt;file://&amp;lt;filename&amp;gt;|grpc://&amp;lt;exporter-address&amp;gt;&amp;gt;&lt;/code&gt; flag, using pulumi version v3.226 or newer. For further documentation see &lt;a href="https://www.pulumi.com/docs/iac/operations/debugging/performance-tracing/#opentelemetry-tracing"&gt;our performance tracing docs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To view the traces, you can use one of the various exporters that exist. Popular options include &lt;a href="https://www.jaegertracing.io/"&gt;Jaeger&lt;/a&gt;, &lt;a href="https://github.com/CtrlSpice/otel-desktop-viewer"&gt;OTel Desktop Viewer&lt;/a&gt;, or &lt;a href="https://github.com/ymtdzzz/otel-tui"&gt;OTel TUI&lt;/a&gt; if you prefer not leaving your terminal. Once you&amp;rsquo;ve ingested the logs there either by uploading the trace file, or sending them directly by giving pulumi the exporter address, look for the &lt;code&gt;pulumi-cli: pulumi&lt;/code&gt; root span.&lt;/p&gt;
&lt;p&gt;All further spans will be parented to that root span, and you should thus be able to see a nice flow diagram in the viewer of your choice.&lt;/p&gt;
&lt;p&gt;As always, we would love any feedback either in the &lt;a href="https://slack.pulumi.com/"&gt;Community Slack&lt;/a&gt;, or through a &lt;a href="https://github.com/pulumi/pulumi/issues"&gt;GitHub issue&lt;/a&gt;.&lt;/p&gt;</description><author>Thomas Gummerer</author><category>features</category><category>pulumi-cli</category></item><item><title>Pulumi IAM Expands: Manage Access at Scale with Tags, Roles, and Teams</title><link>https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/</link><pubDate>Thu, 19 Mar 2026 10:30:00 -0700</pubDate><guid>https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/expanding-pulumi-iam-custom-permissions/index.png" /&gt;
&lt;p&gt;Since the launch of &lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-launch/"&gt;Pulumi IAM&lt;/a&gt; with &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/roles/"&gt;custom roles&lt;/a&gt; and scoped &lt;a href="https://www.pulumi.com/docs/administration/concepts/access-tokens/"&gt;access tokens&lt;/a&gt;, organizations have been using fine-grained permissions to secure their automation and CI/CD pipelines. As teams scale to hundreds or thousands of stacks, environments, and accounts, the next challenge is applying those permissions efficiently.&lt;/p&gt;
&lt;p&gt;Today, we&amp;rsquo;re introducing three new capabilities to help you manage permissions more dynamically at scale: &lt;strong&gt;tag-based access control&lt;/strong&gt;, &lt;strong&gt;team role assignments&lt;/strong&gt;, and &lt;strong&gt;user role assignments&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="why-tag-based-access-control"&gt;Why tag-based access control?&lt;/h2&gt;
&lt;p&gt;With custom roles, you can define granular permissions using &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/scopes/"&gt;fine-grained scopes&lt;/a&gt;. However, applying those roles still requires selecting individual stacks, environments, or accounts one by one. For organizations managing a large number of Pulumi entities, this means either granting overly broad access or spending significant time on manual configuration. Tag-based access control solves this problem.&lt;/p&gt;
&lt;h2 id="whats-new"&gt;What&amp;rsquo;s new?&lt;/h2&gt;
&lt;h3 id="tag-based-access-control"&gt;Tag-based access control&lt;/h3&gt;
&lt;p&gt;You can now create rules within a custom role that dynamically grant permissions based on entity tags. This works across IaC stacks, ESC environments, and Insights accounts. For example, when a new stack is created and tagged &lt;code&gt;env:prod&lt;/code&gt;, anyone with a role containing a matching tag-based rule automatically gets the right permissions. No manual assignment required.&lt;/p&gt;
&lt;p&gt;A single role can include multiple tag-based rules, and they are evaluated with &lt;strong&gt;OR&lt;/strong&gt; logic. If an entity matches any of the rules, the permissions are granted. Within a single rule, you can combine multiple key-value conditions with implicit &lt;strong&gt;AND&lt;/strong&gt; logic for precise targeting. For example, a rule with conditions &lt;code&gt;env:prod&lt;/code&gt; and &lt;code&gt;team:payments&lt;/code&gt; ensures access is granted only to production resources owned by the payments team.&lt;/p&gt;
&lt;h3 id="team-role-assignments"&gt;Team role assignments&lt;/h3&gt;
&lt;p&gt;Custom roles can now be assigned directly to &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/teams/"&gt;teams&lt;/a&gt; within your Pulumi organization. When an engineer joins a team, whether manually or via &lt;a href="https://www.pulumi.com/docs/administration/guides/scim/"&gt;SCIM provisioning&lt;/a&gt;, they automatically inherit the permissions defined in the team&amp;rsquo;s assigned roles.&lt;/p&gt;
&lt;p&gt;Teams support both &lt;strong&gt;inline permissions&lt;/strong&gt; (ad-hoc access to specific stacks, environments, or accounts) and &lt;strong&gt;role-based permissions&lt;/strong&gt; simultaneously. You can assign &lt;strong&gt;multiple roles&lt;/strong&gt; to a single team, giving you full flexibility to compose access from reusable building blocks while retaining the ability to grant one-off access where needed. If you have existing workflows built around ad-hoc assignments to teams, those continue to work exactly as before. You can adopt roles incrementally or mix both approaches on the same team.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Team admins (or users with the &lt;code&gt;team:update&lt;/code&gt; scope) can continue to manage their team&amp;rsquo;s inline permissions as they do today. However, assigning organization-level custom roles to a team requires additional permissions: &lt;code&gt;role:read&lt;/code&gt; and &lt;code&gt;role:update&lt;/code&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="user-role-assignments"&gt;User role assignments&lt;/h3&gt;
&lt;p&gt;Custom roles can also be assigned directly to individual organization members. This is useful for users whose responsibilities span multiple teams or require permissions beyond the existing org-level &lt;code&gt;Admin&lt;/code&gt;, &lt;code&gt;Member&lt;/code&gt;, and &lt;code&gt;Billing Manager&lt;/code&gt; &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/roles/"&gt;roles&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="how-permissions-work-together"&gt;How permissions work together&lt;/h3&gt;
&lt;p&gt;Permissions in Pulumi IAM are &lt;strong&gt;additive&lt;/strong&gt;. A user receives the union of all permissions granted to them, including permissions from roles assigned directly to them as a user and permissions from roles assigned to any team they belong to. A user on both the &amp;ldquo;SRE&amp;rdquo; and &amp;ldquo;Security&amp;rdquo; teams inherits permissions from both team roles, plus any role assigned to them individually.&lt;/p&gt;
&lt;h2 id="how-to-get-started"&gt;How to get started&lt;/h2&gt;
&lt;p&gt;Configuring tag-based access control and role assignments is done through the Pulumi Cloud console and REST API.&lt;/p&gt;
&lt;h3 id="1-create-a-custom-role-with-tag-based-rules"&gt;1. Create a custom role with tag-based rules&lt;/h3&gt;
&lt;p&gt;In Pulumi Cloud, navigate to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Roles&lt;/strong&gt; and create a new custom role. In the role configuration, add tag-based rules that define which entities the role should apply to.&lt;/p&gt;
&lt;p&gt;For example, to create a role that grants write access to all production stacks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create custom role&lt;/strong&gt; and give it a descriptive name (e.g., &amp;ldquo;Production Deployer&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;Add a permission set (e.g., Stack Write) to the role&lt;/li&gt;
&lt;li&gt;Under entity selection, choose &lt;strong&gt;Tag-based rule&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Set the condition: tag key &lt;code&gt;env&lt;/code&gt; equals &lt;code&gt;prod&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Save the role&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="2-assign-the-role-to-a-team"&gt;2. Assign the role to a team&lt;/h3&gt;
&lt;p&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Teams&lt;/strong&gt;, select a team, and assign your custom role. All team members immediately inherit the defined permissions.&lt;/p&gt;
&lt;h3 id="3-assign-a-role-to-an-individual-user"&gt;3. Assign a role to an individual user&lt;/h3&gt;
&lt;p&gt;For users with unique access requirements, go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Access Management&lt;/strong&gt; &amp;gt; &lt;strong&gt;Members&lt;/strong&gt;, select a user, and assign a custom role directly.&lt;/p&gt;
&lt;div class="my-4"&gt;
&lt;video class="flex outline-none rounded-lg w-full" title="Custom roles with tag-based access control"
controls
autoplay muted playsinline
loop &gt;
&lt;source src="abac-demo.mp4" /&gt;
&lt;/video&gt;
&lt;/div&gt;
&lt;h2 id="enforce-tagging-standards-with-pulumi-policy"&gt;Enforce tagging standards with Pulumi Policy&lt;/h2&gt;
&lt;p&gt;Tag-based access control relies on consistent tagging. If a stack is missing a tag or has an incorrect value, permissions won&amp;rsquo;t be applied as expected. &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/"&gt;Pulumi Policy&lt;/a&gt; closes this gap by letting you enforce tagging standards as a &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/"&gt;preventative policy group&lt;/a&gt;, so any &lt;code&gt;pulumi up&lt;/code&gt; on a stack with missing or invalid tags is blocked before deployment. This ensures your tag-based RBAC rules always grant the correct permissions. Policy enforces the standard, RBAC enforces the access.&lt;/p&gt;
&lt;p&gt;To learn how to write policies that validate stack tags, see &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/authoring/#using-stack-tags-in-policies"&gt;Using stack tags in policies&lt;/a&gt;.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;Pulumi Policy currently supports tag enforcement for IaC stacks. For ESC environments and Insights accounts, tags are managed through the Pulumi Cloud console or REST API.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="availability"&gt;Availability&lt;/h2&gt;
&lt;p&gt;Tag-based access control, team role assignments, and user role assignments are available today for customers on the &lt;strong&gt;Pulumi Enterprise&lt;/strong&gt; and &lt;strong&gt;Pulumi Business Critical&lt;/strong&gt; plans. Check out our &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; for more details on editions and what&amp;rsquo;s included.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;With custom roles providing fine-grained permissions, tag-based rules enabling dynamic access policies, and the ability to assign roles directly to teams and users, Pulumi IAM now provides everything you need to implement automated, least-privilege access control at scale. We&amp;rsquo;re excited to see how you leverage these new capabilities to secure and streamline your cloud operations.&lt;/p&gt;
&lt;p&gt;Explore the &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;IAM documentation&lt;/a&gt; to get started, and share your feedback in our &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="learn-more"&gt;Learn more&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;RBAC overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/roles/"&gt;Roles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/permission-sets/"&gt;Permission sets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/teams/"&gt;Teams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/scopes/"&gt;Scopes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-launch/"&gt;Pulumi IAM launch blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/blog/pulumi-cloud-iam-self-hosted/"&gt;Pulumi IAM for self-hosted&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><author>Devon Grove</author><author>Davide Massarenti</author><author>Casey Huang</author><author>Arun Loganathan</author><category>iam</category><category>rbac</category><category>security</category><category>features</category><category>pulumi-cloud</category></item><item><title>From Kubernetes Gatekeeper to Full-Stack Governance with OPA</title><link>https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/</link><pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/kubernetes-gatekeeper-full-stack-governance-opa/index.png" /&gt;
&lt;p&gt;Pulumi&amp;rsquo;s &lt;a href="https://www.openpolicyagent.org/"&gt;OPA (Open Policy Agent)&lt;/a&gt; support is now stable. The &lt;a href="https://github.com/pulumi/pulumi-policy-opa/releases/tag/v1.1.0"&gt;v1.1.0 release&lt;/a&gt; of &lt;code&gt;pulumi-policy-opa&lt;/code&gt; makes OPA/Rego a first-class policy language for Pulumi with full feature parity alongside the native TypeScript and Python policy SDKs. Write Rego policies that validate any resource Pulumi manages, across AWS, Azure, GCP, Kubernetes, and the rest of the provider ecosystem. If you already have &lt;a href="https://open-policy-agent.github.io/gatekeeper/"&gt;Kubernetes Gatekeeper&lt;/a&gt; constraint templates, a new compatibility mode lets you drop those &lt;code&gt;.rego&lt;/code&gt; files directly into a Pulumi policy pack and enforce them against your Kubernetes resources without modification.&lt;/p&gt;
&lt;h2 id="whats-in-the-stable-release"&gt;What&amp;rsquo;s in the stable release&lt;/h2&gt;
&lt;p&gt;OPA/Rego is now fully supported as a policy language for &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/"&gt;Pulumi Insights&lt;/a&gt;, with the same capabilities as the TypeScript and Python SDKs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Resource and stack-level policies&lt;/strong&gt;: Validate individual resources with &lt;code&gt;deny&lt;/code&gt; and &lt;code&gt;warn&lt;/code&gt; rules, or evaluate your entire stack at once with &lt;code&gt;stack_deny&lt;/code&gt; and &lt;code&gt;stack_warn&lt;/code&gt; for cross-resource checks like relationship validation and resource count limits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enforcement levels&lt;/strong&gt;: Control how violations are handled. &lt;code&gt;mandatory&lt;/code&gt; blocks deployments, &lt;code&gt;advisory&lt;/code&gt; surfaces warnings, and &lt;code&gt;disabled&lt;/code&gt; turns rules off without removing them. Enforcement levels can be overridden per policy without modifying Rego source.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Policy configuration&lt;/strong&gt;: Pass custom parameters to policies via configuration files, with optional JSON schema validation. Configuration values are accessible in Rego as &lt;code&gt;data.config.&amp;lt;policy_name&amp;gt;.&amp;lt;key&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPA metadata annotations&lt;/strong&gt;: Use standard OPA &lt;code&gt;# METADATA&lt;/code&gt; comments to provide titles, descriptions, and messages for your policies. These populate the policy metadata displayed in Pulumi Cloud.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preventative and audit evaluation&lt;/strong&gt;: OPA policies work with both &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/"&gt;preventative enforcement&lt;/a&gt; during &lt;code&gt;pulumi up&lt;/code&gt; and &lt;a href="https://www.pulumi.com/blog/policy-audit-scans-for-stacks/"&gt;audit policy scans&lt;/a&gt; for continuous compliance monitoring.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can choose whichever language best fits your team. Organizations already using OPA across their toolchain can standardize on Rego for Pulumi policies, while teams preferring TypeScript or Python can continue to use those. All three languages work side by side in the same &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/"&gt;policy groups&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="kubernetes-gatekeeper-compatibility"&gt;Kubernetes Gatekeeper compatibility&lt;/h2&gt;
&lt;p&gt;The headline feature of this release is native support for &lt;a href="https://open-policy-agent.github.io/gatekeeper/"&gt;Kubernetes Gatekeeper&lt;/a&gt; constraint template rules. If you&amp;rsquo;re running Gatekeeper as an admission controller in your clusters, you likely have a library of &lt;code&gt;.rego&lt;/code&gt; policies that enforce security and operational standards at admission time. With v1.1.0, those same rules can now run as Pulumi policies, catching violations during &lt;code&gt;pulumi preview&lt;/code&gt; before resources ever reach the cluster.&lt;/p&gt;
&lt;p&gt;To enable Gatekeeper compatibility, set &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt; in your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Kubernetes Gatekeeper Policy Pack&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;opa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;inputFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kubernetes-admission&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With this setting, Pulumi automatically wraps Kubernetes resources in the Gatekeeper &lt;a href="https://open-policy-agent.github.io/gatekeeper/website/docs/howto"&gt;AdmissionReview&lt;/a&gt; structure (&lt;code&gt;input.review.object&lt;/code&gt;, &lt;code&gt;input.review.kind&lt;/code&gt;, etc.), so your existing rules work without modification. Non-Kubernetes resources are silently skipped.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example that reuses standard Gatekeeper-style rules, requiring an &lt;code&gt;app&lt;/code&gt; label and prohibiting the &lt;code&gt;latest&lt;/code&gt; image tag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rego" data-lang="rego"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;gatekeeper&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;rego&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# METADATA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# title: Require App Label&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# description: All Kubernetes resources must have an &amp;#34;app&amp;#34; label.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;%s &amp;#39;%s&amp;#39; is missing required label: app&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# METADATA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# title: Disallow Latest Tag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# description: Container images must not use the &amp;#34;latest&amp;#34; tag.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;deny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;contains&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;:latest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;container &amp;#39;%s&amp;#39; uses the &amp;#39;latest&amp;#39; tag -- pin to a specific version&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;These rules are identical to what you&amp;rsquo;d write for Gatekeeper. Both rule head formats are supported and can coexist: the &lt;code&gt;violation[{&amp;quot;msg&amp;quot;: msg}]&lt;/code&gt; map format and the &lt;code&gt;deny[msg]&lt;/code&gt; string format. Per-policy configuration via &lt;code&gt;input.parameters&lt;/code&gt; also works as expected. You can take a &lt;code&gt;.rego&lt;/code&gt; file from your Gatekeeper constraint templates, drop it into a Pulumi policy pack, and publish it to Pulumi Cloud to enforce automatically across your stacks.&lt;/p&gt;
&lt;p&gt;This shifts policy enforcement left. Instead of waiting for the Kubernetes API server to reject a resource at admission time, you catch the violation during &lt;code&gt;pulumi preview&lt;/code&gt;, before anything is deployed.&lt;/p&gt;
&lt;h2 id="walkthrough-reusing-policies-from-the-gatekeeper-library"&gt;Walkthrough: Reusing policies from the gatekeeper-library&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/open-policy-agent/gatekeeper-library"&gt;OPA Gatekeeper Library&lt;/a&gt; is a community-maintained collection of constraint templates covering common Kubernetes guardrails like pod security, image provenance, and resource limits. You can use these policies directly with Pulumi. Here&amp;rsquo;s an end-to-end example using the &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/allowedrepos"&gt;&lt;code&gt;allowedrepos&lt;/code&gt;&lt;/a&gt; policy to restrict which container image registries your deployments can use.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create a new Kubernetes OPA policy pack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy new kubernetes-opa
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy the Rego source from &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/allowedrepos/template.yaml"&gt;gatekeeper-library&lt;/a&gt; into your policy pack as &lt;code&gt;allowedrepos.rego&lt;/code&gt;. No modifications are needed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-rego" data-lang="rego"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k8sallowedrepos&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;container &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initContainers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;initContainer &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;violation&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;review&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ephemeralContainers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_prefix_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ephemeralContainer &amp;lt;%v&amp;gt; has an invalid image repo &amp;lt;%v&amp;gt;, allowed repos are %v&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;repos&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt; has Gatekeeper compatibility enabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Kubernetes Gatekeeper Policy Pack&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;opa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;inputFormat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;kubernetes-admission&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Configure the allowed registries. Create a &lt;code&gt;policy-config.json&lt;/code&gt; file to pass the &lt;code&gt;repos&lt;/code&gt; parameter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;k8sallowedrepos&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repos&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gcr.io/my-company/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;docker.io/library/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test the policy locally against a stack:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi preview --policy-pack . --policy-pack-config policy-config.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Any Kubernetes deployment using an image outside the allowed registries will produce a violation at preview time, before it reaches the cluster.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Publish the pack and add it to a &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/"&gt;policy group&lt;/a&gt; to enforce it across your organization:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pulumi policy publish
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The same approach works for any policy in the gatekeeper-library: &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/containerlimits"&gt;&lt;code&gt;containerlimits&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/requiredlabels"&gt;&lt;code&gt;requiredlabels&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/disallowedtags"&gt;&lt;code&gt;disallowedtags&lt;/code&gt;&lt;/a&gt;, and others. Copy the Rego, configure parameters, and publish.&lt;/p&gt;
&lt;h2 id="part-of-the-pulumi-insights-governance-story"&gt;Part of the Pulumi Insights governance story&lt;/h2&gt;
&lt;p&gt;OPA policy support is part of the broader &lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Pulumi Insights&lt;/a&gt; governance platform. Insights gives you visibility and compliance across your entire cloud footprint, and OPA policies plug directly into that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Audit policy scans&lt;/strong&gt; continuously evaluate OPA policies against your &lt;a href="https://www.pulumi.com/blog/policy-audit-scans-for-stacks/"&gt;Pulumi stacks&lt;/a&gt; and discovered cloud resources, providing a compliance baseline without redeploying anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted execution&lt;/strong&gt; lets you &lt;a href="https://www.pulumi.com/blog/self-hosted-insights/"&gt;run policy evaluations on your own infrastructure&lt;/a&gt; using customer-managed workflow runners, keeping credentials and data within your network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-built compliance packs&lt;/strong&gt; for CIS, NIST, PCI DSS, and other frameworks are available alongside your custom OPA policies in the same &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/"&gt;policy groups&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether you&amp;rsquo;re enforcing policy at deployment time, scanning existing infrastructure for drift, or running continuous compliance checks, OPA policies are a native participant.&lt;/p&gt;
&lt;p&gt;&lt;img src="policy-findings.png" alt="Policy Findings dashboard in Pulumi Cloud showing compliance scores and per-stack policy evaluation results"&gt;&lt;/p&gt;
&lt;h2 id="frequently-asked-questions"&gt;Frequently asked questions&lt;/h2&gt;
&lt;h3 id="do-i-need-to-modify-my-existing-gatekeeper-rego-files"&gt;Do I need to modify my existing Gatekeeper &lt;code&gt;.rego&lt;/code&gt; files?&lt;/h3&gt;
&lt;p&gt;No. Set &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt; in your &lt;code&gt;PulumiPolicy.yaml&lt;/code&gt; and your existing Gatekeeper constraint template rules work as-is. Pulumi handles the AdmissionReview wrapping automatically.&lt;/p&gt;
&lt;h3 id="what-happens-with-non-kubernetes-resources"&gt;What happens with non-Kubernetes resources?&lt;/h3&gt;
&lt;p&gt;When using &lt;code&gt;inputFormat: kubernetes-admission&lt;/code&gt;, non-Kubernetes resources are silently skipped during evaluation. Your Gatekeeper rules only run against Kubernetes resources.&lt;/p&gt;
&lt;h3 id="do-i-need-opa-installed-locally"&gt;Do I need OPA installed locally?&lt;/h3&gt;
&lt;p&gt;No. The &lt;code&gt;pulumi-policy-opa&lt;/code&gt; analyzer plugin embeds the OPA evaluation engine and is installed automatically by the Pulumi CLI (v3.227.0+). The standalone OPA CLI is only needed if you want to run &lt;code&gt;opa test&lt;/code&gt; against your policies independently.&lt;/p&gt;
&lt;h3 id="when-should-i-use-opa-vs-typescript-or-python-for-policies"&gt;When should I use OPA vs. TypeScript or Python for policies?&lt;/h3&gt;
&lt;p&gt;If your team already writes Rego for other tools like Gatekeeper, writing Pulumi policies in Rego keeps your policy language consistent. If your team is more comfortable with general-purpose languages or needs auto-remediation, use the TypeScript or Python SDKs.&lt;/p&gt;
&lt;p&gt;Gatekeeper constraint templates can be reused directly via the &lt;code&gt;kubernetes-admission&lt;/code&gt; input format, but other OPA integrations use different input structures, so those policies would need to be adapted to Pulumi&amp;rsquo;s resource model. All three languages work together in the same policy groups.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Templates are available for &lt;code&gt;kubernetes-opa&lt;/code&gt;, &lt;code&gt;aws-opa&lt;/code&gt;, &lt;code&gt;azure-opa&lt;/code&gt;, and &lt;code&gt;gcp-opa&lt;/code&gt; via &lt;code&gt;pulumi policy new&lt;/code&gt;. For more details, see the &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/authoring/"&gt;policy authoring guide&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/"&gt;Policy as Code overview&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/discovery-governance/policy/"
class="btn btn-primary"
&gt;
Get started with OPA policies
&lt;/a&gt;
&lt;a href="https://github.com/pulumi/pulumi-policy-opa" target="_blank" rel="noopener noreferrer" class="github-card"&gt;
&lt;img
src="https://opengraph.githubassets.com/1/pulumi/pulumi-policy-opa"
alt="GitHub repository: pulumi/pulumi-policy-opa"
class="github-card-image"
loading="lazy"
/&gt;
&lt;div class="github-card-content"&gt;
&lt;div class="github-card-domain"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon github-card-icon" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#b-github"/&gt;&lt;/svg&gt;
github.com/pulumi/pulumi-policy-opa
&lt;/div&gt;
&lt;/div&gt;
&lt;/a&gt;</description><author>Levi Blackstone</author><category>policy-as-code</category><category>features</category><category>opa</category><category>kubernetes</category><category>insights</category></item><item><title>Lock Down Values in Pulumi ESC with fn::final</title><link>https://www.pulumi.com/blog/esc-fn-final/</link><pubDate>Tue, 17 Mar 2026 11:00:00 -0700</pubDate><guid>https://www.pulumi.com/blog/esc-fn-final/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/esc-fn-final/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/esc/"&gt;Pulumi ESC (Environments, Secrets, and Configuration)&lt;/a&gt; allows you to compose environments by importing configuration and secrets from other environments, but this also means a child environment can silently override a value set by a parent. When that value is a security policy or a compliance setting, an accidental override can cause real problems. With the new &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/"&gt;fn::final&lt;/a&gt; built-in function, you can mark values as final, preventing child environments from overriding them. If a child environment tries to override a final value, ESC raises a warning and preserves the original value.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s say you have a parent environment that sets the AWS region for all deployments. You can use &lt;code&gt;fn::final&lt;/code&gt; to ensure no child environment can change it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# project/parent-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fn::final&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;us-east-1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If a child environment tries to override the final value, ESC raises a &lt;code&gt;cannot override final value&lt;/code&gt; warning.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# project/child-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;project/parent-env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;aws-region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;eu-west-1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# raises a warning&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This evaluates to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;aws-region&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;us-east-1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In this scenario, the ESC environment is still valid, but the final value remains unchanged.&lt;/p&gt;
&lt;h2 id="when-to-use-fnfinal"&gt;When to use fn::final&lt;/h2&gt;
&lt;p&gt;Use &lt;code&gt;fn::final&lt;/code&gt; for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security-sensitive values that shouldn&amp;rsquo;t be changed&lt;/li&gt;
&lt;li&gt;Compliance or policy settings enforced by a platform team&lt;/li&gt;
&lt;li&gt;Shared base environments where certain values must remain consistent&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;fn::final&lt;/code&gt; function is available now in all Pulumi ESC environments. For more information, check out the &lt;a href="https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/"&gt;fn::final documentation&lt;/a&gt;!&lt;/p&gt;</description><author>Pablo Terradillos</author><author>Sean Yeh</author><category>esc</category><category>features</category></item><item><title>New: Previous Provider Version Docs in Pulumi Registry</title><link>https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/index.png" /&gt;
&lt;p&gt;The &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; now supports browsing documentation for previous versions of first-party Pulumi providers. If you&amp;rsquo;ve ever needed to look up the API docs for an older provider version, you no longer have to dig through Git history or guess at changes — the docs are right there in the Registry. These docs also help &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt; and other agents more accurately assist you with your Pulumi code and operations.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;When you visit a first-party provider&amp;rsquo;s page in the Pulumi Registry, you&amp;rsquo;ll now see a version dropdown selector that lets you switch between the current version and previous versions.&lt;/p&gt;
&lt;p&gt;&lt;img src="registry-version-picker.png" alt="Version selector dropdown in the Pulumi Registry"&gt;&lt;/p&gt;
&lt;p&gt;Select a previous version from the dropdown, and the Registry loads the full API documentation for that version.&lt;/p&gt;
&lt;h2 id="whats-available"&gt;What&amp;rsquo;s available&lt;/h2&gt;
&lt;p&gt;This feature currently includes documentation for the latest release of each previous major version, going back two major versions. For example, if a provider is on v7.x, you&amp;rsquo;ll be able to view docs for the latest v6.x and v5.x releases in addition to the current version.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Head over to the &lt;a href="https://www.pulumi.com/registry/"&gt;Pulumi Registry&lt;/a&gt; and try it out. Pick any first-party provider with multiple major versions and use the version dropdown to browse its history.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love to hear your feedback — let us know what you think in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or by opening an issue on &lt;a href="https://github.com/pulumi/registry"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/registry/"
class="btn btn-primary"
&gt;
Explore the Pulumi Registry
&lt;/a&gt;</description><author>Cam Soper</author><author>Fausto Núñez Alberro</author><category>registry</category><category>features</category></item><item><title>Pulumi Cloud Now Supports Google Sign-In</title><link>https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/</link><pubDate>Tue, 10 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/pulumi-cloud-now-supports-google-sign-in/index.png" /&gt;
&lt;p&gt;Many developers and platform engineers already use Google accounts daily for email, cloud console access, and collaboration. Until now, signing in to Pulumi Cloud required a &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://gitlab.com/"&gt;GitLab&lt;/a&gt;, or &lt;a href="https://id.atlassian.com/"&gt;Atlassian&lt;/a&gt; account, or an email/password combination. Today, we&amp;rsquo;re adding Google as a first-class identity provider, so you can sign in to Pulumi Cloud with the same Google account you already use for everything else.&lt;/p&gt;
&lt;p&gt;Adding Google as an identity provider brings several benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use the account you already have. If your team already lives in &lt;a href="https://workspace.google.com/"&gt;Google Workspace&lt;/a&gt;, you can sign in to Pulumi Cloud with a single click, no new credentials required.&lt;/li&gt;
&lt;li&gt;Inherit your existing security policies. If you&amp;rsquo;ve already configured two-factor authentication, device management, and other protections in a Google Workspace, you can carry them over to Pulumi Cloud automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;h3 id="signing-up-or-signing-in"&gt;Signing up or signing in&lt;/h3&gt;
&lt;p&gt;On the Pulumi Cloud sign-in page, you&amp;rsquo;ll see a new &lt;strong&gt;Sign in with Google&lt;/strong&gt; button alongside the existing GitHub, GitLab, and Atlassian options. If you are a new user, select it, authenticate with your Google account, and you&amp;rsquo;re in.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;If you already have an existing Pulumi Cloud account, make sure to associate to your existing account as described in the next section.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="sign-in.png" alt="Pulumi Cloud sign-in page showing Google as an identity provider option"&gt;&lt;/p&gt;
&lt;h3 id="connecting-google-to-an-existing-account"&gt;Connecting Google to an existing account&lt;/h3&gt;
&lt;p&gt;If you already have a Pulumi Cloud account, you can link your Google identity from your account settings:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to your &lt;a href="https://app.pulumi.com/account/settings"&gt;Account Settings&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Scroll to the &lt;strong&gt;Identity providers&lt;/strong&gt; section.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Available identities&lt;/strong&gt;, select &lt;strong&gt;Connect Google&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once connected, you can use Google to sign in to your existing Pulumi Cloud account.&lt;/p&gt;
&lt;p&gt;&lt;img src="connected-identities.png" alt="Account settings showing connected identities including Google"&gt;&lt;/p&gt;
&lt;h3 id="google-sign-in-vs-saml-sso"&gt;Google sign-in vs. SAML SSO&lt;/h3&gt;
&lt;p&gt;Google sign-in lets you authenticate with Pulumi Cloud using your individual Google account. It does not enable Google as a single sign-on (SSO) identity provider for your Pulumi Cloud organization.&lt;/p&gt;
&lt;p&gt;If your team uses Google Workspace and needs centralized membership governance for Pulumi Cloud, configure &lt;a href="https://www.pulumi.com/docs/administration/guides/saml/gsuite/"&gt;SAML SSO with Google Workspace&lt;/a&gt; instead. SAML SSO is available on Pulumi Enterprise and Business Critical editions.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Google sign-in is available now for all new and existing Pulumi Cloud users:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New users&lt;/strong&gt;: &lt;a href="https://app.pulumi.com/signup"&gt;Sign up with Google&lt;/a&gt; on the Pulumi Cloud sign-up page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Existing users&lt;/strong&gt;: &lt;a href="https://app.pulumi.com/account/settings"&gt;Connect your Google account&lt;/a&gt; in your account settings.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more details, see the &lt;a href="https://www.pulumi.com/docs/administration/organizations-teams/accounts/"&gt;Pulumi Cloud accounts documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;d love to hear your feedback. Join the conversation in the &lt;a href="https://slack.pulumi.com"&gt;Pulumi Community Slack&lt;/a&gt; or open an issue on &lt;a href="https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Pablo Seibelt</author><author>Casey Huang</author><category>features</category><category>security</category><category>authentication</category><category>pulumi-cloud</category></item><item><title>Expanded Version Control Support in Pulumi Cloud</title><link>https://www.pulumi.com/blog/expanded-version-control-support/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/expanded-version-control-support/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/expanded-version-control-support/index.png" /&gt;
&lt;p&gt;Your version control provider shouldn&amp;rsquo;t limit your infrastructure workflows. Pulumi Cloud now works with &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/#github-enterprise-server-support"&gt;GitHub Enterprise Server&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;. Every team gets the same &lt;a href="https://www.pulumi.com/docs/deployments/concepts/"&gt;deployment pipelines&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/deployments/concepts/review-stacks/"&gt;PR previews&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/ai/"&gt;AI-powered change summaries&lt;/a&gt; regardless of where their code lives.&lt;/p&gt;
&lt;p&gt;&lt;img src="VCS.png" alt="Add account screen showing GitHub, GitLab, and Azure DevOps as VCS options"&gt;&lt;/p&gt;
&lt;h2 id="connect-multiple-providers-and-accounts"&gt;Connect multiple providers and accounts&lt;/h2&gt;
&lt;p&gt;You can connect multiple VCS providers to a single Pulumi organization simultaneously, like GitHub, GitLab, and Azure DevOps all at once. You can also connect multiple accounts of the same provider, such as two separate GitHub organizations or two GitLab groups. This means teams that work across different repositories, providers, or organizational boundaries can manage everything from one place.&lt;/p&gt;
&lt;div class="note note-info"&gt;
&lt;div class="icon-and-line"&gt;
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--fill" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-info-fill"/&gt;&lt;/svg&gt;
&lt;div class="line"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="content"&gt;GitHub Enterprise Server is currently limited to one connection per Pulumi organization.&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="what-your-team-can-do"&gt;What your team can do&lt;/h2&gt;
&lt;h3 id="deploy-on-every-push"&gt;Deploy on every push&lt;/h3&gt;
&lt;p&gt;Connect a repository to a stack, and infrastructure deploys automatically when you push. Configure path filters to trigger only when relevant files change, and manage environment variables and secrets directly in Pulumi Cloud. No external CI/CD pipeline required.&lt;/p&gt;
&lt;h3 id="preview-changes-on-pull-requests"&gt;Preview changes on pull requests&lt;/h3&gt;
&lt;p&gt;Every pull request gets an infrastructure preview so reviewers can see exactly what will change before merging. The preview runs the same Pulumi operations your deployment would, giving your team confidence that a merge won&amp;rsquo;t break anything.&lt;/p&gt;
&lt;h3 id="neo-explains-your-changes"&gt;Neo explains your changes&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/product/neo/"&gt;Neo&lt;/a&gt; posts AI-generated summaries on your pull requests explaining what infrastructure changes mean in plain language. Reviewers who aren&amp;rsquo;t Pulumi experts can still understand the impact of a change without reading resource diffs.&lt;/p&gt;
&lt;p&gt;&lt;img src="ado-prcomments.png" alt="Neo posting an infrastructure change summary on a pull request"&gt;&lt;/p&gt;
&lt;h3 id="let-neo-open-pull-requests-for-you"&gt;Let Neo open pull requests for you&lt;/h3&gt;
&lt;p&gt;Ask Neo to make infrastructure changes and it opens pull requests directly against your connected repositories. Describe what you want in natural language, and Neo writes the code, opens the PR, and kicks off a preview, all without leaving Pulumi Cloud.&lt;/p&gt;
&lt;h3 id="detect-and-fix-drift"&gt;Detect and fix drift&lt;/h3&gt;
&lt;p&gt;Schedule &lt;a href="https://www.pulumi.com/docs/deployments/concepts/drift/"&gt;drift detection&lt;/a&gt; to catch out-of-band changes automatically. When someone modifies infrastructure outside of your Pulumi programs, drift detection flags the difference so your team can remediate before it causes issues.&lt;/p&gt;
&lt;h3 id="secure-authentication"&gt;Secure authentication&lt;/h3&gt;
&lt;p&gt;Pulumi Cloud authenticates with your VCS provider using OIDC or OAuth so no long-lived credentials need to be stored. Short-lived tokens keep your deployment pipelines secure without manual secret rotation.&lt;/p&gt;
&lt;h3 id="set-up-new-projects-from-your-vcs"&gt;Set up new projects from your VCS&lt;/h3&gt;
&lt;p&gt;The new project wizard discovers your organizations, repositories, and branches so you can scaffold and deploy a new stack without leaving Pulumi Cloud. Pick your repo, choose a branch, and you&amp;rsquo;re ready to deploy.&lt;/p&gt;
&lt;p&gt;&lt;img src="ado-npw.png" alt="New project wizard showing repository settings"&gt;&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;An org admin configures the integration under &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Version Control&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Authorize with your VCS provider.&lt;/li&gt;
&lt;li&gt;Deploy infrastructure with first-class workflows.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For setup details, see the docs for &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/"&gt;GitHub&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/github-app/#github-enterprise-server-support"&gt;GitHub Enterprise Server&lt;/a&gt;, &lt;a href="https://www.pulumi.com/docs/integrations/version-control/azure-devops-integration/"&gt;Azure DevOps&lt;/a&gt;, and &lt;a href="https://www.pulumi.com/docs/integrations/version-control/gitlab/"&gt;GitLab&lt;/a&gt;.&lt;/p&gt;
&lt;a
href="https://app.pulumi.com/signin"
class="btn btn-primary"
target="_blank"
rel="noopener noreferrer"
&gt;
Connect your VCS
&lt;svg xmlns="http://www.w3.org/2000/svg" class="ph-icon ph-icon--regular text-sm ml-2" fill="currentColor" aria-hidden="true" focusable="false"&gt;&lt;use href="https://www.pulumi.com/icons/sprite.233e2a8e44d77c3fb864f7b6741050b277d317a225202560ecc3ea43f8ea27de.svg#p-arrow-square-out-regular"/&gt;&lt;/svg&gt;
&lt;/a&gt;</description><author>Luke Ward</author><author>Michael Fallihee</author><author>Boris Schlosser</author><author>Dan Biwer</author><category>features</category><category>pulumi-cloud</category><category>azure</category><category>github</category><category>gitlab</category></item><item><title>Now Generally Available: Store Terraform State in Pulumi Cloud</title><link>https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/terraform-state-backend-pulumi-cloud/index.png" /&gt;
&lt;p&gt;Platform engineering teams managing infrastructure across Terraform and Pulumi now have a way to unify state management without rewriting a single line of HCL. Starting today, Pulumi Cloud can serve as a &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Terraform state backend&lt;/a&gt;, letting you store and manage Terraform state alongside your Pulumi stacks. Your team continues using the Terraform or OpenTofu CLI for day-to-day operations while gaining the benefits of Pulumi Cloud: AI-powered infrastructure management with &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Pulumi Neo&lt;/a&gt; — our infrastructure agent — encrypted state storage, update history, state locking, role-based access control, audit policies, and unified resource visibility through &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/"&gt;Insights&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This feature is now generally available.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;Most organizations adopting Pulumi are not starting from scratch. They have years of Terraform deployments spread across teams, and migrating everything to a new IaC tool overnight is not realistic. We have heard from customers who are excited about the power of Pulumi Cloud but have had to manage migration projects before they can fully benefit from centralized visibility and governance.&lt;/p&gt;
&lt;p&gt;The Terraform state backend in Pulumi Cloud changes that equation. Instead of requiring a full code conversion before teams see value, you can migrate your state in minutes and immediately unlock Pulumi Cloud capabilities for your existing Terraform infrastructure — including Neo, Pulumi&amp;rsquo;s AI infrastructure agent. Once your Terraform state is in Pulumi Cloud, Neo can reason about those resources the same way it does for Pulumi IaC stacks: finding resources, troubleshooting issues, understanding dependencies, and writing infrastructure code PRs. Teams that prefer Terraform can keep using it, while platform engineers get a single AI-powered control plane across the entire infrastructure estate.&lt;/p&gt;
&lt;h2 id="what-you-get"&gt;What you get&lt;/h2&gt;
&lt;p&gt;When you store Terraform state in Pulumi Cloud, your Terraform-managed resources get the following added functionality:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agentic infrastructure with Neo.&lt;/strong&gt; &lt;a href="https://www.pulumi.com/docs/ai/"&gt;Neo&lt;/a&gt;, Pulumi&amp;rsquo;s AI infrastructure agent, works across your entire cloud footprint — Terraform and Pulumi IaC alike. Once your Terraform state is in Pulumi Cloud, you can ask Neo to find resources across both tools, trace dependencies that span Terraform and Pulumi stacks, troubleshoot configuration issues, and generate new infrastructure code informed by your existing resources. This means platform teams get a single AI-powered interface regardless of which IaC tool manages each piece of infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Encrypted state with update history.&lt;/strong&gt; State is encrypted in transit and at rest. Every change is tracked as a versioned checkpoint visible in the &lt;a href="https://www.pulumi.com/docs/iac/concepts/stacks/#stack-activity"&gt;stack activity tab&lt;/a&gt;, giving you full rollback capability. This is a common concern for teams currently storing state in S3 buckets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Automatic state locking.&lt;/strong&gt; Pulumi Cloud prevents concurrent Terraform operations from corrupting state, without requiring you to configure DynamoDB tables or other external locking mechanisms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Role-based access control.&lt;/strong&gt; Control who can read or modify each stack using &lt;a href="https://www.pulumi.com/docs/administration/concepts/rbac/"&gt;teams and RBAC&lt;/a&gt;, applying the same access policies you use for Pulumi stacks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unified resource visibility.&lt;/strong&gt; View Terraform-managed resources alongside Pulumi-managed resources in &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/search/"&gt;Resource Search&lt;/a&gt;. Each Terraform resource appears in the console using a &lt;code&gt;pulumi:terraform:&amp;lt;tf-type&amp;gt;&lt;/code&gt; naming convention, so you can search and filter using the attribute names you already know.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Audit policies.&lt;/strong&gt; Run &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/"&gt;audit (detective) policy packs&lt;/a&gt; against your Terraform-managed stacks, including Pulumi&amp;rsquo;s &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/pre-built-packs/"&gt;pre-built compliance packs&lt;/a&gt; for CIS, PCI, and more. Pulumi Cloud performs a best-effort schema mapping from Terraform resource shapes to Pulumi provider equivalents, so existing policy packs work without modification in most cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Stack outputs and references.&lt;/strong&gt; Terraform root module outputs are automatically mapped to Pulumi &lt;a href="https://www.pulumi.com/docs/iac/concepts/stacks/#outputs"&gt;stack outputs&lt;/a&gt;, making them available via &lt;a href="https://www.pulumi.com/docs/iac/concepts/stacks/#stackreferences"&gt;stack references&lt;/a&gt; and the &lt;a href="https://www.pulumi.com/docs/esc/providers/iac/pulumi-stacks/"&gt;&lt;code&gt;pulumi-stacks&lt;/code&gt; ESC provider&lt;/a&gt;. This is useful for sharing foundational infrastructure like VPC IDs or DNS zones between Terraform and Pulumi stacks, and for incremental migrations where legacy infrastructure stays in Terraform while new stacks are written in Pulumi.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Pulumi Cloud implements the &lt;a href="https://developer.hashicorp.com/terraform/language/backend/remote"&gt;Terraform remote backend API&lt;/a&gt;. You point the Terraform CLI at Pulumi Cloud using the standard &lt;code&gt;backend &amp;quot;remote&amp;quot;&lt;/code&gt; configuration block, and no changes to your Terraform code or workflow are required.&lt;/p&gt;
&lt;p&gt;Each Terraform workspace maps to a Pulumi stack. The workspace name follows the convention &lt;code&gt;&amp;lt;project&amp;gt;_&amp;lt;stack&amp;gt;&lt;/code&gt;. For example, &lt;code&gt;networking_prod&lt;/code&gt; creates a stack named &lt;code&gt;prod&lt;/code&gt; in the &lt;code&gt;networking&lt;/code&gt; project.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Migration from S3, Azure Blob, GCS, local backends, or HCP Terraform (Terraform Cloud) takes minutes and is documented in the &lt;a href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"&gt;Terraform state backend guide&lt;/a&gt;. From S3, Azure Blob, GCS, or local state, back up your state, update your backend block to point to Pulumi Cloud, set &lt;code&gt;TF_TOKEN_api_pulumi_com&lt;/code&gt;, and run &lt;code&gt;terraform init -migrate-state&lt;/code&gt;. From HCP Terraform, export state manually and push it to Pulumi Cloud.&lt;/p&gt;
&lt;p&gt;Each Terraform resource stored in Pulumi Cloud counts as a resource under management, the same as a Pulumi-managed resource. See the &lt;a href="https://www.pulumi.com/pricing/"&gt;pricing page&lt;/a&gt; for details.&lt;/p&gt;
&lt;a
href="https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/"
class="btn btn-primary"
&gt;
Store Terraform State in Pulumi Cloud
&lt;/a&gt;
&lt;p&gt;If you have questions or feedback, join us in the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or open an issue on &lt;a href="https://github.com/pulumi/pulumi"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;</description><author>Claire Gaestel</author><category>releases</category><category>features</category><category>terraform</category><category>pulumi-cloud</category><category>infrastructure-as-code</category></item><item><title>Now GA: Up to 20x Faster Pulumi Operations for Everyone</title><link>https://www.pulumi.com/blog/journaling-ga/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><guid>https://www.pulumi.com/blog/journaling-ga/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/journaling-ga/index.png" /&gt;
&lt;p&gt;In January, we &lt;a href="https://www.pulumi.com/blog/journaling/"&gt;introduced a major performance enhancement for Pulumi Cloud&lt;/a&gt; through a fundamental change to how Pulumi manages state that speeds up operations by up to 20x. After a staged rollout across many organizations, &lt;strong&gt;it is now enabled by default for every Pulumi Cloud operation&lt;/strong&gt;. No opt-in required—just use Pulumi CLI v3.225.0+ with Pulumi Cloud. The improvement applies to &lt;code&gt;pulumi up&lt;/code&gt;, &lt;code&gt;pulumi destroy&lt;/code&gt;, and &lt;code&gt;pulumi refresh&lt;/code&gt;; &lt;code&gt;pulumi preview&lt;/code&gt; does not modify state, so it is unchanged.&lt;/p&gt;
&lt;h2 id="what-this-means-for-you"&gt;What this means for you&lt;/h2&gt;
&lt;p&gt;First and foremost, nothing about how you work with &lt;code&gt;pulumi&lt;/code&gt; needs to change. Your updates now benefit from better parallelism and should thus complete faster. Before this change, &lt;code&gt;pulumi&lt;/code&gt; always saved a full snapshot to the cloud, so the current state could always be recovered if something goes wrong. With journaling, we now only send the state of each operation, which allows us to send these updates in parallel, as long as resources are not related to each other. For the full deep dive, see the blog post linked above.&lt;/p&gt;
&lt;h2 id="production-results"&gt;Production results&lt;/h2&gt;
&lt;p&gt;Since January, we&amp;rsquo;ve had many early adopters of journaling. This helped us shake out one final bug on the server side, and journaling has been stable since then. With that we feel confident in rolling this out to all our users.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve also gathered some real-world data on how journaling is performing. The data from the preview period shows some significant improvements for update times. For stacks with fewer than 100 resources, the median improvement is 25.3%, while the p90 improvement is 75.2%, and we&amp;rsquo;ve seen a p99 improvement of up to 92.6% Meanwhile, for larger stacks, the median improvement is 60.2%. We need more data for stacks with more than 100 resources, we will update this blog once that comes in.&lt;/p&gt;
&lt;p&gt;This data already shows the expected significant improvement in update times, especially for larger stacks, though the improvements strongly depend on the shape and type of resources that are being set up. Stacks with many resources, that are quick to update benefit more than smaller stacks with slower to set up resources. For more numbers see also the &lt;a href="https://www.pulumi.com/blog/journaling/#benchmarks"&gt;Benchmarks section in the previous blog post&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="what-you-need-to-do"&gt;What you need to do&lt;/h2&gt;
&lt;p&gt;While this was an opt-in process using the &lt;code&gt;PULUMI_ENABLE_JOURNALING&lt;/code&gt; environment variable, this opt-in is no longer required. Just upgrade your Pulumi CLI to v3.225.0+ and use the Pulumi Cloud backend, and journaling will automatically speed up your updates.&lt;/p&gt;
&lt;p&gt;If you encounter any issues, reach out on the &lt;a href="https://slack.pulumi.com/"&gt;Pulumi Community Slack&lt;/a&gt; or through &lt;a href="https://www.pulumi.com/support/new/"&gt;Pulumi Support&lt;/a&gt;. You can also set the &lt;code&gt;PULUMI_DISABLE_JOURNALING=true&lt;/code&gt; env variable to opt out of journaling.&lt;/p&gt;</description><author>Thomas Gummerer</author><author>Pat Gavlin</author><category>performance</category><category>pulumi-cloud</category><category>features</category><category>releases</category></item><item><title>Run Pulumi Insights on Your Own Infrastructure</title><link>https://www.pulumi.com/blog/self-hosted-insights/</link><pubDate>Mon, 02 Mar 2026 00:06:00 -0700</pubDate><guid>https://www.pulumi.com/blog/self-hosted-insights/</guid><description>
&lt;img src="https://www.pulumi.com/images/generated/blog/self-hosted-insights/index.png" /&gt;
&lt;p&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Pulumi Insights&lt;/a&gt; gives you visibility and governance across your entire cloud footprint: &lt;strong&gt;discovery scans&lt;/strong&gt; catalog every resource in your cloud accounts, and &lt;strong&gt;policy evaluations&lt;/strong&gt; continuously enforce compliance against those resources. Until now, Insights workflows ran exclusively on Pulumi-hosted infrastructure. That works well for many teams, but enterprises with strict data residency requirements, private network constraints, or regulatory obligations need to run this work in their own environments. Today, Pulumi Insights supports &lt;a href="https://www.pulumi.com/docs/deployments/concepts/customer-managed-runners/"&gt;customer-managed workflow runners&lt;/a&gt; for both SaaS Pulumi Cloud and &lt;a href="https://www.pulumi.com/docs/administration/self-hosting/"&gt;self-hosted Pulumi Cloud&lt;/a&gt; installations.&lt;/p&gt;
&lt;h2 id="insights-at-a-glance"&gt;Insights at a glance&lt;/h2&gt;
&lt;p&gt;Insights provides two complementary capabilities that together form a governance lifecycle for your cloud infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Discovery&lt;/strong&gt; scans cloud accounts across &lt;a href="https://aws.amazon.com/"&gt;AWS&lt;/a&gt;, &lt;a href="https://azure.microsoft.com/"&gt;Azure&lt;/a&gt;, &lt;a href="https://cloud.google.com/"&gt;GCP&lt;/a&gt;, and more to catalog every resource regardless of how it was provisioned: Pulumi, &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, &lt;a href="https://aws.amazon.com/cloudformation/"&gt;CloudFormation&lt;/a&gt;, or manual creation. Once cataloged, you can search, filter, group, and &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/data-export/"&gt;export&lt;/a&gt; your resource data. You can also &lt;a href="https://www.pulumi.com/docs/discovery-governance/discovery/visual-import/"&gt;import&lt;/a&gt; unmanaged resources into Pulumi to bring them under IaC management.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Policy&lt;/strong&gt; enforces compliance with policy-as-code written in &lt;a href="https://www.typescriptlang.org/"&gt;TypeScript&lt;/a&gt; or &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt;. Pulumi ships &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-packs/pre-built-packs/"&gt;pre-built compliance packs&lt;/a&gt; for CIS, NIST, PCI DSS, HITRUST, and other frameworks so you can start evaluating without writing any code. &lt;a href="https://www.pulumi.com/docs/discovery-governance/policy/policy-groups/#types-of-policy-groups"&gt;Audit policy groups&lt;/a&gt; continuously evaluate all discovered resources and IaC stacks, while preventative policies block non-compliant deployments before they reach production.&lt;/p&gt;
&lt;p&gt;This enables you to map out your cloud estate, evaluate compliance, and then remediate any issues uncovered by policy.&lt;/p&gt;
&lt;h2 id="why-self-hosted"&gt;Why self-hosted?&lt;/h2&gt;
&lt;p&gt;Running Insights on your own infrastructure with &lt;a href="https://www.pulumi.com/docs/deployments/concepts/customer-managed-runners/"&gt;customer-managed workflow runners&lt;/a&gt; gives you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Data residency&lt;/strong&gt;: Scan execution and policy evaluation run entirely within your private network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private infrastructure access&lt;/strong&gt;: Scan resources in VPCs and environments that are not accessible from the public internet.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compliance&lt;/strong&gt;: Cloud provider credentials can stay internal to your network, meeting regulatory requirements for credential handling.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flexible hosting&lt;/strong&gt;: Run workflow runners on any environment that meets your needs, including Linux, macOS, &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;, and &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="how-it-works"&gt;How it works&lt;/h2&gt;
&lt;p&gt;Customer-managed workflow runners are lightweight agents that poll Pulumi Cloud for pending work, execute it locally, and report results back. You can configure runners to handle specific workflow types: discovery scans, policy evaluations, deployments, or all three.&lt;/p&gt;
&lt;p&gt;This works identically whether you use SaaS Pulumi Cloud or a self-hosted installation. The runner communicates with the Pulumi Cloud API over HTTPS, so no inbound connectivity is required, making it well suited to run in restricted network environments.&lt;/p&gt;
&lt;p&gt;Under the hood, this is powered by a distributed work scheduling system that routes activities to the right runner pool, handles lease-based execution, and recovers automatically from failures. For a deep dive on the architecture, see &lt;a href="https://www.pulumi.com/blog/how-we-built-a-distributed-work-scheduling-system-for-pulumi-cloud/"&gt;How We Built a Distributed Work Scheduling System for Pulumi Cloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If your team already uses customer-managed workflow runners for &lt;a href="https://www.pulumi.com/docs/deployments/"&gt;Pulumi Deployments&lt;/a&gt;, your existing runner pools can handle Insights workflows with no additional infrastructure.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;p&gt;Self-hosted Insights is available on the Business Critical edition of Pulumi Cloud. To learn more or get set up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/self-hosted/"&gt;Self-hosted Insights documentation&lt;/a&gt; — configuration and setup for discovery scans and audit policy evaluations on your own infrastructure&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/deployments/concepts/customer-managed-runners/"&gt;Customer-managed workflow runners&lt;/a&gt; — runner installation, configuration reference, and pool management&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/docs/discovery-governance/"&gt;Insights &amp;amp; Governance overview&lt;/a&gt; — full documentation for discovery and policy capabilities&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.pulumi.com/contact/?form=sales"&gt;Contact sales&lt;/a&gt; to enable self-hosted Insights for your organization&lt;/li&gt;
&lt;/ul&gt;</description><author>Levi Blackstone</author><category>insights</category><category>features</category><category>pulumi-cloud</category><category>policy-as-code</category></item></channel></rss>