{"id":"src_jjcTPC7jQ256vfihHZAgC","slug":"pulumi-blog","name":"Pulumi Blog","type":"feed","url":"https://www.pulumi.com/blog/","orgId":"org_CXx7IPNbZpLaDROi03ZTh","org":{"slug":"pulumi","name":"Pulumi"},"isPrimary":false,"metadata":"{\"evaluatedMethod\":\"feed\",\"evaluatedAt\":\"2026-04-11T13:59:04.992Z\",\"feedUrl\":\"https://www.pulumi.com/blog/rss.xml\",\"feedType\":\"rss\",\"feedDiscoveredAt\":\"2026-04-11T13:59:04.992Z\",\"noFeedFound\":false,\"feedEtag\":\"W/\\\"c43f0f5912fdd96a51a7c66d9c17394b\\\"\",\"feedLastModified\":\"Sat, 18 Apr 2026 20:14:06 GMT\"}","releaseCount":53,"releasesLast30Days":10,"avgReleasesPerWeek":3.2,"latestVersion":null,"latestDate":"2026-04-14T09:00:00.000Z","changelogUrl":null,"hasChangelogFile":false,"lastFetchedAt":"2026-04-18T01:03:37.248Z","trackingSince":"2025-12-16T00:00:00.000Z","releases":[{"id":"rel_It24-ysYX7RPhAGRk4nfo","version":null,"title":"Scan AWS GovCloud and more partitions with Pulumi Insights","summary":"![](https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/meta.png)\n\nPulumi Insights account scanning now supports every AWS partit...","content":"![](https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/meta.png)\n\nPulumi 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.\n\n## Supported partitions\n\n- AWS Standard (Commercial)\n\n- AWS GovCloud (US)\n\n- AWS ISO (US)\n\n- AWS ISOB (US)\n\n- AWS ISOF (US)\n\n- AWS ISOE (Europe)\n\n- AWS European Sovereign Cloud\n\n- AWS China\n\nYou can also exclude specific regions from discovery — useful when regions are disabled by SCPs or fall outside an audit&rsquo;s scope.\n\n![Choosing an AWS partition when creating an Insights account](aws-partition-picker.png)\n\n## Discovery stays inside the partition\n\nCredentials are exchanged against the partition&rsquo;s STS endpoint, and every scanner API call targets that partition&rsquo;s regional endpoints. Discovery traffic doesn&rsquo;t cross the boundary.\n\n## Set it up\n\nIn the Pulumi Cloud console:\n\n- Go to **Accounts → Create account**.\n\n- Select **AWS** as the provider.\n\n- Under **Add your configuration**, pick the target partition.\n\n- Supply credentials via a Pulumi ESC environment. The OIDC trust policy uses the partition-appropriate ARN prefix (`arn:aws-us-gov:`, `arn:aws-cn:`, etc.).\n\nFor IAM and ESC setup, see the [Insights accounts docs](https://www.pulumi.com/docs/insights/discovery/accounts/). Log in to [Pulumi Cloud](https://app.pulumi.com/) to get started.","publishedAt":"2026-04-14T09:00:00.000Z","url":"https://www.pulumi.com/blog/scan-aws-govcloud-china-with-pulumi-insights/","media":[]},{"id":"rel_lssYQn_lR3RIWyguOgtCX","version":null,"title":"Superpowers, GSD, and GSTACK: Picking the Right Framework for Your Coding Agent","summary":"![](https://www.pulumi.com/blog/claude-code-orchestration-frameworks/meta.png)\n\nThree community frameworks have emerged that fix the specific ways AI ...","content":"![](https://www.pulumi.com/blog/claude-code-orchestration-frameworks/meta.png)\n\nThree community frameworks have emerged that fix the specific ways AI coding agents break down on real projects. [Superpowers](https://github.com/obra/superpowers) enforces test-driven development. [GSD](https://github.com/gsd-build/get-shit-done) prevents context rot. [GSTACK](https://github.com/garrytan/gstack) adds role-based governance. All three started with Claude Code but now work across Cursor, Codex, Windsurf, Gemini CLI, and more.\n\nPulumi uses general-purpose programming languages to define infrastructure. TypeScript, Python, Go, C#, Java. Every framework that makes AI agents write better TypeScript also makes your `pulumi up` better. After spending a few weeks with each one, I have opinions about when to use which.\n\n## The problem all three frameworks solve\n\nAI coding agents are impressive for the first 30 minutes. Then things go sideways. The patterns are predictable enough that three separate teams independently built frameworks to fix them.\n\n**Context rot.** Every LLM has a context window. As that window fills up, earlier instructions fade. You start a session asking for an [S3 bucket](https://www.pulumi.com/docs/iac/clouds/aws/guides/) with AES-256 encryption, proper ACLs, and access logging. Two hours and 200K tokens later, the agent creates a new bucket with none of those requirements. The context window got crowded and your original instructions lost weight.\n\n**No test discipline.** Agents write code that looks plausible. Plausible code compiles. Plausible code even runs, for a while. But plausible code without tests is a liability. The agent adds a feature and quietly breaks two others because nothing verified the existing behavior was preserved.\n\n**Scope drift.** You ask for a [VPC with three subnets](https://www.pulumi.com/docs/iac/clouds/aws/guides/vpc/). The agent decides you also need a NAT gateway, a transit gateway, a VPN endpoint, and a custom DNS resolver. Helpful in theory. In practice, you now have infrastructure you never requested and barely understand. You will also pay for it monthly.\n\nThese problems are not specific to Claude Code or any particular agent. They happen with Cursor, Codex, Windsurf, and every other LLM-powered coding tool. The context window does not care which brand name is on the wrapper.\n\n## Superpowers: the test-driven discipline enforcer\n\n[Superpowers](https://github.com/obra/superpowers) was created by [Jesse Vincent](https://www.linkedin.com/in/jessevincent/) and has accumulated over 149K GitHub stars. The core idea is simple: no production code gets written without a failing test first.\n\nThe framework enforces a 7-phase workflow. Brainstorm the approach. Write a spec. Create a plan. Write failing tests (TDD). Spin up subagents to implement. Review. Finalize. Every phase has gates. You cannot skip ahead. The iron law is that production code only exists to make a failing test pass.\n\nThis sounds rigid. It is. That is the point.\n\nSuperpowers includes a Visual Companion for design decisions, which helps when you are making architectural choices that need visual reasoning. The main orchestrator manages the entire workflow from a single context window, delegating implementation work to subagents that run in isolation.\n\nThe tradeoff is that the mega-orchestrator pattern means the orchestrator itself can hit context limits on very long sessions. One big brain coordinating everything works well until the big brain fills up. For most projects, this is not an issue. For marathon sessions with dozens of files, keep it in mind.\n\nThe workflow breaks down into skills that trigger automatically:\n\nSkill\nPhase\nWhat it does\n\n`brainstorming`\nDesign\nRefines rough ideas through Socratic questions, saves design doc\n\n`writing-plans`\nPlanning\nBreaks work into 2-5 minute tasks with exact file paths and code\n\n`test-driven-development`\nImplementation\nRED-GREEN-REFACTOR: failing test first, minimal code, commit\n\n`subagent-driven-development`\nImplementation\nDispatches fresh subagent per task with two-stage review\n\n`requesting-code-review`\nReview\nReviews against plan, blocks progress on critical issues\n\n`finishing-a-development-branch`\nFinalize\nVerifies tests pass, presents merge/PR/keep/discard options\n\nThe results speak for themselves. The [chardet](https://github.com/chardet/chardet) maintainer used Superpowers to rewrite chardet v7.0.0 from scratch, achieving a 41x performance improvement. Not a 41% improvement. 41 times faster. That is what happens when every code change has to pass a test: the agent optimizes aggressively because it has a safety net.\n\nSuperpowers works with Claude Code, Cursor, Codex, OpenCode, GitHub Copilot CLI, and Gemini CLI.\n\n## GSD: preventing context rot before it ruins your project\n\n[GSD](https://github.com/gsd-build/get-shit-done) (Get Shit Done) was created by [Lex Christopherson](https://www.linkedin.com/in/lexchristopherson/) and has over 51K stars. Where Superpowers focuses on test discipline, GSD attacks the context window problem directly.\n\nThe key architectural decision: GSD does not use a single mega-orchestrator. Instead, it assigns a separate orchestrator to each phase of work. Each orchestrator stays under 50% of its context capacity. When a phase completes, the orchestrator writes its state to disk as Markdown files, then a fresh orchestrator picks up where the last one left off.\n\nThink about why this matters. With a single orchestrator, your 200K token context window is a shared resource. Instructions from hour one compete with code from hour three. GSD sidesteps this entirely. Every phase starts with a full context budget because the previous phase&rsquo;s orchestrator handed off cleanly and shut down.\n\nThe state files use XML-formatted instructions because (it turns out) LLMs parse structured XML more reliably than freeform Markdown. GSD also includes quality gates that detect schema drift and scope reduction. If the agent starts cutting corners or wandering from the plan, the gates catch it.\n\nGSD evolved from v1 (pure Markdown configuration) to v2 (TypeScript SDK), which tells you something about the level of engineering behind it. The v2 SDK gives you programmatic control over orchestration, not just static instruction files.\n\nThe tradeoff: GSD has more ceremony than the other two frameworks. For a quick script or a single-file change, the phase-based workflow is overkill. GSD earns its keep on projects that span multiple files, multiple sessions, or multiple days.\n\nThe core commands map to a phase-based workflow:\n\nCommand\nWhat it does\n\n`/gsd-new-project`\nFull initialization: questions, research, requirements, roadmap\n\n`/gsd-discuss-phase`\nCapture implementation decisions before planning starts\n\n`/gsd-plan-phase`\nResearch, plan, and verify for a single phase\n\n`/gsd-execute-phase`\nExecute all plans in parallel waves, verify when complete\n\n`/gsd-verify-work`\nManual user acceptance testing\n\n`/gsd-ship`\nCreate PR from verified phase work with auto-generated body\n\n`/gsd-fast`\nInline trivial tasks, skips planning entirely\n\nGSD supports the widest range of agents: 14 and counting. Claude Code, Cursor, Windsurf, Codex, Copilot, Gemini CLI, Cline, Augment, Trae, Qwen Code, and more.\n\n## GSTACK: when you need a whole team, not just an engineer\n\n[GSTACK](https://github.com/garrytan/gstack) was created by [Garry Tan](https://www.linkedin.com/in/garrytan/) (CEO of Y Combinator) and has over 71K stars. It takes a fundamentally different approach from the other two frameworks.\n\nInstead of disciplining a single agent, GSTACK models a 23-person team. CEO, product manager, QA lead, engineer, designer, security reviewer. Each role has its own responsibilities, its own constraints, and its own slice of the problem.\n\nThe framework enforces five layers of constraint. Role focus keeps each specialist in their lane. Data flow controls what information passes between roles. Quality control gates ensure standards at handoff points. The &ldquo;boil the lake&rdquo; principle means each role finishes what it can do perfectly and skips what it cannot, rather than producing mediocre work across everything. And the simplicity layer pushes back against unnecessary complexity.\n\nThe role isolation is what makes GSTACK distinctive. The engineer role does not see the product roadmap. The QA role does not see the implementation details. Each role only receives the context it needs to do its job. This is not just about efficiency. It prevents the kind of scope creep where an agent that knows everything tries to do everything.\n\n&ldquo;Boil the lake&rdquo; is my favorite principle across all three frameworks. It is the opposite of how most agents work. Agents default to attempting everything and producing something mediocre. GSTACK says: do fewer things, but do them right.\n\nThe tradeoff: 23 specialist roles feels heavy for pure infrastructure work. If you are writing Pulumi programs and deploying cloud resources with [component resources](https://www.pulumi.com/docs/iac/concepts/components/), you probably do not need a product manager role or a designer role. GSTACK shines when you are building a product, not just provisioning infrastructure.\n\nEach slash command activates a different specialist:\n\nCommand\nRole\nWhat it does\n\n`/office-hours`\nYC partner\nSix forcing questions that reframe your product before you write code\n\n`/plan-ceo-review`\nCEO\nFour modes: expand scope, selective expand, hold, reduce\n\n`/plan-eng-review`\nEngineering manager\nLock architecture, map data flow, list edge cases\n\n`/review`\nStaff engineer\nFind bugs that pass CI but break in production, auto-fix the obvious ones\n\n`/qa`\nQA lead\nReal Playwright browser testing, not simulated\n\n`/ship`\nRelease engineer\nOne-command deploy with coverage audit\n\n`/cso`\nSecurity officer\nOWASP and STRIDE security audits\n\nGSTACK works with Claude Code, Codex CLI, OpenCode, Cursor, Factory Droid, Slate, and Kiro.\n\n## Where each framework fits\n\nSuperpowers\nGSD\nGSTACK\n\nWhat it locks down\nThe dev process itself\nThe execution environment\nWho decides what\n\nOrchestration\nSingle orchestrator\nPer-phase orchestrators\n23 specialist roles\n\nContext management\nOne window\nState-to-disk, fresh per phase\nRole-scoped handoffs\n\nWhere it shines\nTDD, subagent delegation, disciplined plan execution\nMarathon sessions, parallel workstreams, crash recovery\nProduct strategy, multi-perspective review, real browser QA\n\nWhere it struggles\nAnything beyond the build phase\nOverkill for small tasks, no role separation\nThe actual writing-code part\n\nBest for\nSolo devs who need test discipline\nComplex projects that span days or weeks\nFounder-engineers shipping a product\n\nGitHub stars\n149K\n51K\n71K\n\nAgent support\n6 agents\n14+ agents\n7 agents\n\nFor infrastructure work, GSD&rsquo;s context management matters most. Long Pulumi sessions that provision dozens of resources across multiple stacks are exactly the scenario where context rot bites hardest. GSD&rsquo;s phase-based approach keeps each orchestrator fresh.\n\nSuperpowers&rsquo; TDD workflow maps well to application code where unit tests are straightforward. Infrastructure testing is different. You cannot unit test whether an [IAM policy](https://www.pulumi.com/docs/iac/clouds/aws/guides/iam/) actually grants the right permissions. You can test the shape of the policy with [Pulumi&rsquo;s testing frameworks](https://www.pulumi.com/docs/iac/guides/testing/), but the real validation happens at [`pulumi preview`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_preview/) and [`pulumi up`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_up/). Superpowers still helps here (discipline is discipline), but the TDD cycle is less natural for infra than for app code.\n\nGSTACK shines when the project has product dimensions. If you are building a SaaS platform where the infrastructure serves a product vision, GSTACK&rsquo;s multi-role governance keeps the product thinking connected to the engineering work. For pure infra provisioning, the extra roles add overhead without much benefit.\n\nMy honest take: none of these is universally best. Knowing your failure mode is the real decision.\n\nWhat keeps going wrong\nTry this\nThe reason\n\nCode works today, breaks tomorrow\nSuperpowers\nForces every change through a failing test first\n\nQuality drops after the first hour\nGSD\nFresh context per phase, nothing carries over\n\nYou ship features nobody asked for\nGSTACK\nProduct review before engineering starts\n\nAll of the above\nGSTACK for direction, bolt on Superpowers TDD\nNo single framework covers everything yet\n\n## Combining frameworks with Pulumi workflows\n\nThese frameworks solve the &ldquo;how&rdquo; of agent orchestration. [Skills](https://www.pulumi.com/blog/top-8-claude-skills-devops-2026/) (like the ones from [Pulumi Agent Skills](https://github.com/pulumi/agent-skills)) solve the &ldquo;what,&rdquo; teaching agents the right patterns for specific technologies. Frameworks and skills complement each other. A skill tells the agent to use [OIDC](https://www.pulumi.com/docs/esc/guides/configuring-oidc/aws/) instead of hardcoded credentials. A framework makes sure the agent still remembers that instruction 200K tokens later.\n\nGSD&rsquo;s state-to-disk approach pairs naturally with [Pulumi stack outputs](https://www.pulumi.com/docs/iac/concepts/inputs-outputs/). Each phase can read the previous phase&rsquo;s stack outputs from the state files, so a networking phase can provision a VPC and the compute phase can reference the subnet IDs without any context window gymnastics.\n\nSuperpowers&rsquo; TDD cycle maps to infrastructure validation. Write a failing test (the expected shape of your infrastructure). Run [`pulumi preview`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_preview/) (red, the resources do not exist yet). Run [`pulumi up`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_up/) (green, the infrastructure matches the test). This is not a perfect analogy since infrastructure tests are broader than unit tests, but the discipline of &ldquo;verify before moving on&rdquo; translates directly.\n\nYou do not have to pick one framework and commit forever. Try GSD for a long multi-stack project. Try Superpowers for a focused library. See which failure mode bites you most and let that guide your choice.\n\n## Getting started\n\n[\n![GitHub repository: obra/superpowers](https://opengraph.githubassets.com/1/obra/superpowers)\n\n**\ngithub.com/obra/superpowers\n\n](https://github.com/obra/superpowers)\n[\n![GitHub repository: gsd-build/get-shit-done](https://opengraph.githubassets.com/1/gsd-build/get-shit-done)\n\n**\ngithub.com/gsd-build/get-shit-done\n\n](https://github.com/gsd-build/get-shit-done)\n[\n![GitHub repository: garrytan/gstack](https://opengraph.githubassets.com/1/garrytan/gstack)\n\n**\ngithub.com/garrytan/gstack\n\n](https://github.com/garrytan/gstack)\n\nAll three frameworks support multiple agents. For Claude Code, the install commands are straightforward:\n\n```\n# Superpowers\n/plugin install superpowers@claude-plugins-official\n\n# GSD (the installer asks which agents and whether to install globally or locally)\nnpx get-shit-done-cc@latest\n\n# GSTACK\ngit clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setup\n\n```\n\nCheck each repository&rsquo;s README for Cursor, Codex, Windsurf, and other agents.\n\nIf you want a managed experience that handles orchestration for you, [Pulumi Neo](https://www.pulumi.com/product/neo/) is [grounded in your actual infrastructure](https://www.pulumi.com/blog/grounded-ai-why-neo-knows-your-infrastructure/), not internet patterns. It understands your stacks, your dependencies, and your deployment history. The [10 things you can do with Neo](https://www.pulumi.com/blog/10-things-you-can-do-with-neo/) post shows what that looks like in practice.\n\nPick one and give it a project. You will know within an hour whether it fixes your particular failure mode.\n\n[\nTry Pulumi for Free\n](https://www.pulumi.com/docs/get-started/)","publishedAt":"2026-04-13T00:00:00.000Z","url":"https://www.pulumi.com/blog/claude-code-orchestration-frameworks/","media":[]},{"id":"rel_6q2SouJAwkmoX19LeWGqz","version":null,"title":"Introducing Bun as a Runtime for Pulumi","summary":"![](https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/meta.png)\n\nLast year we added support for [Bun as a package manager](https://w...","content":"![](https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/meta.png)\n\nLast year we added support for [Bun as a package manager](https://www.pulumi.com/blog/bun-package-manager/) for Pulumi TypeScript projects. Today we&rsquo;re taking the next step: Bun is now a fully supported runtime for Pulumi programs. Set `runtime: bun` in your `Pulumi.yaml` and Bun will execute your entire Pulumi program, with no Node.js required. Since Bun&rsquo;s 1.0 release, this has been one of our [most requested features](https://github.com/pulumi/pulumi/issues/13904).\n\n## Why Bun?\n\n[Bun](https://bun.sh/) 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:\n\n- **Native TypeScript support**: Bun runs TypeScript directly without requiring [ts-node](https://typestrong.org/ts-node/) or a separate compile step.\n\n- **Fast package management**: Bun&rsquo;s built-in package manager can install dependencies significantly faster than npm.\n\n- **Node.js compatibility**: Bun [aims for 100% Node.js compatibility](https://bun.sh/docs/runtime/nodejs-apis), so the npm packages you already use with Pulumi should work out of the box.\n\nWith `runtime: bun`, Pulumi uses Bun for both running your program and managing your packages, giving you a streamlined single-tool experience.\n\n## Getting started\n\nTo create a new Pulumi project with the Bun runtime, run:\n\n```\npulumi new bun\n\n```\n\nThis creates a TypeScript project configured to use Bun. The generated `Pulumi.yaml` looks like this:\n\n```\nname: my-bun-project\nruntime: bun\n\n```\n\nFrom here, write your Pulumi program as usual. For example, to create a random password using the `@pulumi/random` package:\n\n```\nbun add @pulumi/random\n\n```\n\n```\nimport * as random from \"@pulumi/random\";\n\nconst password = new random.RandomPassword(\"password\", {\n length: 20,\n});\n\nexport const pw = password.result;\n\n```\n\nThen deploy with:\n\n```\npulumi up\n\n```\n\n**Prerequisites:**\n\n- [Bun](https://bun.sh/docs/installation) 1.3 or later\n\n- [Pulumi](https://www.pulumi.com/docs/iac/download-install/) 3.227.0 or later\n\n## Converting existing Node.js projects\n\nIf you have an existing Pulumi TypeScript project running on Node.js, you can convert it to use the Bun runtime in a few steps.\n\n### 1. Update `Pulumi.yaml`\n\nChange the `runtime` field from `nodejs` to `bun`:\n\nBefore:\n\n```\nruntime:\n name: nodejs\n options:\n packagemanager: npm\n\n```\n\nAfter:\n\n```\nruntime: bun\n\n```\n\n**\n\nWhen the runtime is set to `bun`, Bun is also used as the package manager — there&rsquo;s no need to configure a separate `packagemanager` option.\n\n### 2. Update `tsconfig.json`\n\nBun handles TypeScript differently from Node.js with `ts-node`. Update your `tsconfig.json` to use [Bun&rsquo;s recommended compiler options](https://bun.sh/docs/typescript#suggested-compileroptions):\n\n```\n{\n \"compilerOptions\": {\n \"lib\": [\"ESNext\"],\n \"target\": \"ESNext\",\n \"module\": \"Preserve\",\n \"moduleDetection\": \"force\",\n \"moduleResolution\": \"bundler\",\n \"allowJs\": true,\n \"allowImportingTsExtensions\": true,\n \"verbatimModuleSyntax\": true,\n \"strict\": true,\n \"skipLibCheck\": true,\n \"noFallthroughCasesInSwitch\": true,\n \"noUncheckedIndexedAccess\": true,\n \"noImplicitOverride\": true\n }\n}\n\n```\n\nKey differences from a typical Node.js `tsconfig.json`:\n\n- [`module: \"Preserve\"`](https://www.typescriptlang.org/tsconfig/#module) and [`moduleResolution: \"bundler\"`](https://devblogs.microsoft.com/typescript/announcing-typescript-5-0/#moduleresolution-bundler): Let Bun handle module resolution instead of compiling to CommonJS. The `bundler` resolution strategy allows extensionless imports while still respecting `package.json` exports, matching how Bun resolves modules in practice.\n\n- [`verbatimModuleSyntax: true`](https://www.typescriptlang.org/tsconfig/#verbatimModuleSyntax): Enforces consistent use of ESM `import`/`export` syntax. TypeScript will flag any remaining CommonJS patterns like `require()` at compile time.\n\n### 3. Switch to ESM\n\nBun makes it easy to go full ESM and it&rsquo;s the [recommended module format](https://bun.sh/docs/runtime/module-resolution) for Bun projects. Add `\"type\": \"module\"` to your `package.json`:\n\n```\n{\n \"type\": \"module\"\n}\n\n```\n\nWith [ECMAScript module (ESM)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) 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 [async entrypoint function](https://github.com/docs/iac/languages-sdks/javascript/#enabling-async-support). With ESM and Bun, [top-level await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#top_level_await) just works, so you can skip the wrapper function entirely and `await` directly at the module level:\n\n```\nimport * as aws from \"@pulumi/aws\";\n\nconst azs = await aws.getAvailabilityZones({ state: \"available\" });\n\nconst buckets = azs.names.map(az => new aws.s3.BucketV2(`my-bucket-${az}`));\n\nexport const bucketNames = buckets.map(b => b.id);\n\n```\n\nIf your existing program does use an async entrypoint with `export =`, just replace it with the ESM-standard `export default`:\n\n```\n// CommonJS (Node.js default)\nexport = async () => {\n const bucket = new aws.s3.BucketV2(\"my-bucket\");\n return { bucketName: bucket.id };\n};\n\n// ESM (used with Bun)\nexport default async () => {\n const bucket = new aws.s3.BucketV2(\"my-bucket\");\n return { bucketName: bucket.id };\n};\n\n```\n\n### 4. Update the Pulumi SDK\n\nMake sure you&rsquo;re running `@pulumi/pulumi` version 3.226.0 or later:\n\n```\nbun add @pulumi/pulumi@latest\n\n```\n\n### 5. Install dependencies and deploy\n\n```\npulumi install\npulumi up\n\n```\n\n## Bun as runtime vs. Bun as package manager\n\nWith this release, there are now two ways to use Bun with Pulumi:\n\nConfiguration\nBun&rsquo;s role\nNode.js required?\n\n`runtime: bun`\nRuns your program and manages packages\nNo\n\n`runtime: { name: nodejs, options: { packagemanager: bun } }`\nManages packages only\nYes\n\nUse `runtime: bun` for the full Bun experience. The package-manager-only mode is still available for projects that need Node.js-specific features like function serialization.\n\n## Known limitations\n\nThe following Pulumi features are not currently supported when using the Bun runtime:\n\n**\n\n- **[Callback functions (magic lambdas)](https://www.pulumi.com/docs/iac/clouds/aws/guides/lambda/)** are not supported. APIs like `aws.lambda.CallbackFunction` and event handler shortcuts (e.g., `bucket.onObjectCreated`) use [function serialization](https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/) which requires Node.js `v8` and `inspector` modules that are only partially supported in Bun.\n\n- **[Dynamic providers](https://www.pulumi.com/docs/iac/concepts/providers/dynamic-providers/)** are not supported. Dynamic providers (`pulumi.dynamic.Resource`) similarly rely on [function serialization](https://www.pulumi.com/docs/iac/concepts/functions/function-serialization/).\n\nIf your project uses any of these features, continue using `runtime: nodejs`. You can still benefit from Bun&rsquo;s fast package management by setting `packagemanager: bun` in your runtime options.\n\n## Start using Bun with Pulumi\n\nBun runtime support is available now in [Pulumi 3.227.0](https://www.pulumi.com/docs/iac/download-install/). To get started:\n\n- Create a new project: `pulumi new bun`\n\n- Read the docs: [TypeScript (Node.js) SDK](https://www.pulumi.com/docs/iac/languages-sdks/javascript/)\n\n- Report issues or share feedback on [GitHub](https://github.com/pulumi/pulumi/issues) or in the [Pulumi Community Slack](https://slack.pulumi.com)\n\nThank you to everyone who upvoted, commented on, and contributed to [the original feature request](https://github.com/pulumi/pulumi/issues/13904). Your feedback helped shape this feature, and we&rsquo;d love to hear how it works for you.","publishedAt":"2026-04-08T00:00:00.000Z","url":"https://www.pulumi.com/blog/introducing-bun-as-a-runtime-for-pulumi/","media":[]},{"id":"rel_j1I9XYGzcvpG5b13KqWby","version":null,"title":"Automate Azure App Secret Rotation with ESC","summary":"![](https://www.pulumi.com/blog/automate-azure-app-secret-rotation-with-esc/meta.png)\n\n[Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/fu...","content":"![](https://www.pulumi.com/blog/automate-azure-app-secret-rotation-with-esc/meta.png)\n\n[Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/fundamentals/whatis) (formerly Azure Active Directory) is Azure&rsquo;s identity and access management service. Any time your application needs to authenticate with Entra ID, you create an **app registration** and give it a [client secret](https://learn.microsoft.com/en-us/entra/identity-platform/how-to-add-credentials?tabs=client-secret) that proves its identity. But those secrets expire, and if you don&rsquo;t rotate them in time, your app loses access.\n\nIf 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 [Pulumi ESC](https://www.pulumi.com/docs/esc)&rsquo;s `azure-app-secret` rotator, you can automate client secret rotation for your Azure apps, so you never have to worry about expired credentials again.\n\n## Setup\n\n### Prerequisites\n\n- An Azure App Registration\n\n- An [azure-login](https://www.pulumi.com/docs/esc/integrations/dynamic-login-credentials/azure-login/) environment\n\nNote for OIDC users: Since Azure does not support wildcard subject matches, you will need to add a [federated credential](https://www.pulumi.com/docs/esc/guides/configuring-oidc/azure/#add-federated-credentials) for the azure-login environment as well as each environment that imports it.\n\n- The Azure identity used for rotation must have the `Application.ReadWrite.All` Graph API permission, or the identity must be added as an Owner of the specific app registration whose secrets will be rotated.\n\n## How it works\n\nLet&rsquo;s assume your azure-login environment looks like this:\n\n```\n# my-org/logins/production\nvalues:\n azure:\n login:\n fn::open::azure-login:\n clientId: \n tenantId: \n subscriptionId: \n oidc: true\n\n```\n\nCreate a new environment for your rotator. If you have the existing credentials, set them in the [state](https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-rotate/#parameters) object so the rotator will treat them as the `current` credentials.\n\n```\n# my-org/rotators/secret-rotator\nvalues:\n appSecret:\n fn::rotate::azure-app-secret:\n inputs:\n login: ${environments.logins.production.azure.login}\n clientId: \n lifetimeInDays: 180 # How long each new secret is valid (max 730 days)\n state:\n current:\n secretId: \n secretValue:\n fn::secret: \n\n```\n\nThe `lifetimeInDays` 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 [schedule](https://www.pulumi.com/docs/esc/environments/rotation/#schedule) that runs before the lifetime expires so your credentials are always fresh.\n\nAzure app registrations can have at most two client secrets at any given time, so the rotator maintains a `current` and `previous` secret. When a rotation occurs, the existing `current` secret becomes the `previous` secret, and a new secret is created to take its place as the new `current`. This ensures a smooth rollover with no downtime, since the previous secret remains valid until the next rotation.\n\nOnce this is set up, you&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.\n\n## Learn more\n\nThe `fn::rotate::azure-app-secret` rotator is available now in all Pulumi ESC environments. For more information, check out the [fn::rotate::azure-app-secret documentation](https://www.pulumi.com/docs/esc/integrations/rotated-secrets/azure-app-secret/)!","publishedAt":"2026-04-06T00:00:00.000Z","url":"https://www.pulumi.com/blog/automate-azure-app-secret-rotation-with-esc/","media":[]},{"id":"rel_QroPP9JH3b8LtvNwYCqZN","version":null,"title":"Introducing the pulumi policy analyze Command for Existing Stacks","summary":"![](https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/meta.png)\n\nYou can now run [policy packs](https://www.pulumi.com/docs/insights/p...","content":"![](https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/meta.png)\n\nYou can now run [policy packs](https://www.pulumi.com/docs/insights/policy/policy-packs/) against your existing stack state without running your Pulumi program or making provider calls. The new `pulumi policy analyze` command evaluates your current infrastructure against local policy packs directly, turning policy validation into a fast, repeatable check.\n\n## Why this command matters\n\nPolicy authoring and policy updates usually involve an iteration loop:\n\n- Make a policy change.\n\n- Run a policy check.\n\n- Inspect violations or remediations.\n\n- Repeat until the policy behavior matches intent.\n\nBefore this command, that loop often depended on [`pulumi preview`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_preview/) or [`pulumi up`](https://www.pulumi.com/docs/iac/cli/commands/pulumi_up/), which can be heavier than you need when your goal is validating policy logic against known state.\n\nWith `pulumi policy analyze`, you can evaluate your current stack state directly and quickly.\n\n## Basic usage\n\nAt minimum, provide a policy pack path and optionally a stack:\n\n```\npulumi policy analyze \\\n --policy-pack ./policy-pack \\\n --stack dev\n\n```\n\nYou can also pass a config file for each policy pack:\n\n```\npulumi policy analyze \\\n --policy-pack ./policy-pack \\\n --policy-pack-config ./policy-config.dev.json \\\n --stack dev\n\n```\n\nIf any mandatory policy violations are found, the command exits non-zero.\n\nIf remediation policies fire, those changes are reported in output, but stack state is not modified.\n\n## Testing new policy packs as a developer\n\nFor policy pack development, this command is useful as a tight local feedback loop:\n\n- Pick a representative stack (`dev`, `staging`, or a fixture stack).\n\n- Run `pulumi policy analyze` against that stack after each policy change.\n\n- Use the output to verify mandatory, advisory, and remediation behavior.\n\n- Repeat before publishing the policy pack or attaching it to broader policy groups.\n\nTwo output modes are especially useful:\n\n- `--diff` for a concise, human-readable view while iterating locally.\n\n- `--json` for structured output that can be consumed in scripts and CI.\n\n## Using it in AI and agent workflows\n\nThis command is also a good primitive for AI-assisted policy workflows.\n\nBecause `pulumi policy analyze` can emit JSON and a clear process exit code, agents can use it for deterministic policy evaluation steps:\n\n- Propose or edit policy rules.\n\n- Run `pulumi policy analyze --json` against target stacks.\n\n- Parse violations and remediation signals.\n\n- Suggest policy fixes, config adjustments, or targeted infrastructure changes.\n\n- Re-run analysis until mandatory violations are resolved.\n\nFor example, an agent tasked with fixing a policy violation can run `pulumi policy analyze --json` 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.\n\nThis works well for automation because the command doesn&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.\n\n## Try it out\n\n`pulumi policy analyze` is available in [Pulumi v3.229.0](https://github.com/pulumi/pulumi/releases/tag/v3.229.0). Upgrade with:\n\n```\nbrew upgrade pulumi\n# or\npulumi self-update\n\n```\n\nIf 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.\n\nFor implementation details, see the merged PR: [pulumi/pulumi#22250](https://github.com/pulumi/pulumi/pull/22250).\n\n[\nGet started with policy as code\n](https://www.pulumi.com/docs/insights/policy/)","publishedAt":"2026-04-03T00:00:00.000Z","url":"https://www.pulumi.com/blog/pulumi-policy-analyze-existing-stacks/","media":[]},{"id":"rel_9AffiBrmJENgLkAh8kwer","version":null,"title":"KubeCon EU 2026 Recap: The Year AI Moved Into Production on Kubernetes","summary":"![](https://www.pulumi.com/blog/kubecon-eu-2026-recap/meta.png)\n\nAmsterdam in late March still has that sharp North Sea wind, but inside the RAI Conve...","content":"![](https://www.pulumi.com/blog/kubecon-eu-2026-recap/meta.png)\n\nAmsterdam in late March still has that sharp North Sea wind, but inside the RAI Convention Centre, 13,350 people generated enough energy to heat the building twice over. [KubeCon + CloudNativeCon EU 2026](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe-2026/) was the biggest European edition yet, and the shift from previous years was impossible to miss. AI dominated the conference.\n\nI spent most of the conference at the Pulumi booth, and that turned out to be the best vantage point. Hundreds of visitors stopped by over four days, and I kept asking the same question: what are you actually running in production with AI on Kubernetes? The answers shaped this post more than any keynote did. Almost everyone had a proof of concept. Almost nobody had a production story they were happy with.\n\n![The Pulumi crew at our booth at KubeCon EU 2026 in Amsterdam](pulumi-booth.jpg)\n\nHere is the stat that framed the entire conference for me: [66% of organizations use Kubernetes to host generative AI workloads, but only 7% deploy to production daily](https://www.cncf.io/reports/the-cncf-annual-cloud-native-survey/). That gap between experimentation and actual production use matched what I was hearing at the booth. The CNCF&rsquo;s own survey now counts [19.9 million cloud native developers worldwide, 7.3 million of them building AI workloads](https://www.cncf.io/reports/state-of-cloud-native-development-q1-2026/). The tooling and the infrastructure need to catch up.\n\nMy takeaway after four days on the ground: lots of working demos, very few production setups people trust. Teams are trying to scale inference, put guardrails around agents, and make GPU infrastructure behave like anything else they run.\n\nHere is what I saw.\n\n## From training to inference: the big pivot\n\nAbout [67% of AI compute now goes to inference](https://www.deloitte.com/us/en/insights/industry/technology/technology-media-and-telecom-predictions/2026/compute-power-ai.html), not training. The inference market is projected to hit [$255 billion by 2030](https://www.marketsandmarkets.com/Market-Reports/ai-inference-market-189921964.html). It&rsquo;s also where most of the operational complexity lives.\n\nNVIDIA leaned into this hard. Their open-source stack around [NeMo](https://github.com/NVIDIA-NeMo/NeMo) and [Dynamo](https://github.com/ai-dynamo/dynamo) got significant stage time, but the bigger move was donating three projects to the CNCF: the [DRA driver](https://github.com/NVIDIA/k8s-dra-driver-gpu) for fractional GPU allocation, the [KAI Scheduler](https://github.com/kai-scheduler/KAI-Scheduler) for GPU-aware scheduling, and [Grove](https://github.com/ai-dynamo/grove). Moving these to community governance signals that GPU infra is becoming part of the standard Kubernetes toolkit.\n\n## The CNCF donations that will reshape AI on Kubernetes\n\nEvery KubeCon has its crop of new CNCF projects, but this year&rsquo;s batch felt different. We are starting to see the building blocks of an AI runtime for Kubernetes.\n\n[**llm-d**](https://github.com/llm-d/llm-d) was the headline donation. Created by IBM Research, Red Hat, and Google Cloud, it splits inference workloads by separating prefill and decode phases across different pods. The collaborator list reads like an industry consortium: NVIDIA, CoreWeave, AMD, Cisco, Hugging Face, Intel, Lambda, Mistral AI, UC Berkeley, and UChicago. When that many organizations agree on a single approach to distributed inference, pay attention.\n\nNVIDIA&rsquo;s [**DRA driver**](https://github.com/NVIDIA/k8s-dra-driver-gpu) enables fractional GPU allocation and multi-node NVLink support. GPU multi-tenancy is one of the hardest unsolved problems in Kubernetes right now. Scheduling, isolation, cost attribution — all of it breaks down when multiple workloads share a GPU. The DRA driver does not solve everything, but it gives the community a real starting point.\n\n[**KAI Scheduler**](https://github.com/kai-scheduler/KAI-Scheduler) entered the CNCF Sandbox for GPU-aware scheduling. If llm-d handles the inference runtime and the DRA driver handles allocation, KAI Scheduler handles placement. Together, these three projects form the skeleton of a GPU-native Kubernetes stack.\n\n[**Velero**](https://github.com/vmware-tanzu/velero), donated by Broadcom, moved into CNCF Sandbox for backup and restore. AI workloads are stateful now (model weights, checkpoints, fine-tuning data), and backup is no longer optional. Good timing.\n\n[**Microsoft AI Runway**](https://github.com/kaito-project/airunway) is an open-source Kubernetes API for inference that plugs in Hugging Face model discovery, GPU memory fit calculations, and cost estimates. Think of it as a model-aware control plane. [**HolmesGPT**](https://github.com/HolmesGPT/holmesgpt) and [**Dalec**](https://github.com/project-dalec/dalec), also from Microsoft, entered CNCF Sandbox for AI-powered troubleshooting and dependency analysis.\n\nThe **Kubernetes AI Conformance Program** is growing fast, with certifications nearly doubled and three new requirements proposed for Kubernetes 1.36. Conformance programs are boring until they are not. This one will determine which distributions can credibly claim AI readiness.\n\n## Agentic AI gets an identity layer\n\nIf inference was this year&rsquo;s production story, agentic AI was the architecture story. Agents are proliferating, and nobody has quite figured out how to manage and secure them inside Kubernetes yet.\n\n[**kagent**](https://github.com/kagent-dev/kagent), donated to CNCF Sandbox by Solo.io, defines agents as Kubernetes CRDs. It ships with pre-built [MCP](https://github.com/modelcontextprotocol/modelcontextprotocol) (Model Context Protocol) servers for Kubernetes, Istio, Helm, Argo, Prometheus, Grafana, and Cilium. An agent becomes a first-class Kubernetes resource, schedulable and observable and subject to RBAC, instead of a rogue process running in someone&rsquo;s notebook.\n\n[**kagenti**](https://github.com/kagenti/kagenti) from IBM goes after the identity problem directly. Using [SPIFFE/SPIRE](https://github.com/spiffe/spire), it gives agents cryptographic identities. When an agent calls an API, you can verify exactly which agent made the call, what trust domain it belongs to, and whether it is authorized. This kind of security work needs to happen before agents proliferate across production clusters. Retrofitting identity later is ugly.\n\n[**Dapr Agents**](https://github.com/dapr/dapr-agents) took a different angle with the actor model and durable execution. Each agent gets reliable state management and exactly-once messaging semantics. If your workflows cannot tolerate lost messages or duplicate actions, this matters.\n\n[**agentregistry**](https://github.com/agentregistry-dev/agentregistry) showed up as a centralized discovery service for MCP servers and agents. As agents and tool servers multiply, you need a registry to find and manage them, the same way container registries became necessary for images.\n\nDavid Soria Parra from Anthropic gave a talk on [MCP evolving beyond simple tool-calling](https://blog.modelcontextprotocol.io/posts/2026-mcp-roadmap/) into richer interaction patterns ([sched](https://colocatedeventseu2026.sched.com/event/2E7Db/agentics-day-mcp-+-agents-mcp-in-2026-context-is-all-you-need-david-soria-parra-anthropic)). Google announced the [**Kubernetes Agent Sandbox**](https://github.com/kubernetes-sigs/agent-sandbox) for running agentic AI workloads in secure, isolated environments.\n\n## AI gateways and inference routing\n\nGateway infrastructure had its own mini-conference within KubeCon. The [Gateway API Inference Extension](https://github.com/kubernetes-sigs/gateway-api-inference-extension) from the Kubernetes SIG introduces model-aware routing and load balancing at the gateway level. Instead of routing by URL path, your gateway routes by model name, version, and capacity. That changes how inference traffic flows through a cluster in a fundamental way.\n\n[**Envoy AI Gateway**](https://github.com/envoyproxy/ai-gateway) builds on [Envoy](https://github.com/envoyproxy/envoy)&rsquo;s existing proxy capabilities with token-aware rate limiting and provider failover. If your primary inference provider is saturated, traffic shifts to a secondary automatically. Rate limiting by token count rather than request count makes much more sense for LLM workloads, where a single request can consume vastly different amounts of compute.\n\nI want to call out [**Agentgateway**](https://github.com/agentgateway/agentgateway) specifically. Written in Rust, it proxies LLM traffic, MCP connections, and agent-to-agent communication, with [Cedar](https://github.com/cedar-policy/cedar) and [CEL](https://github.com/google/cel-spec) policy engines for fine-grained access control. Rust&rsquo;s performance characteristics matter here because inference gateway latency adds directly to user-perceived response time.\n\n[**Kuadrant**](https://github.com/Kuadrant/kuadrant-operator), now in CNCF Sandbox, layers policy on top of gateway infrastructure and includes MCP server aggregation. Gateways are evolving from dumb traffic proxies into intelligent control planes for AI workloads, and these four projects are driving that shift.\n\n## Platform engineering absorbs LLMOps\n\nThe observability and platform engineering vendors showed up in force. The message was consistent: LLMOps is just platform engineering with new requirements.\n\n**Chronosphere** demonstrated parallel AI investigation, with multiple agents analyzing different aspects of an incident simultaneously and combining their findings. **SUSE Liz** takes a domain-specialized approach, deploying different AI agents for different operational domains rather than one general-purpose assistant. **groundcover** combines eBPF with [OpenTelemetry](https://opentelemetry.io/) to give coding agents rich runtime context about the systems they are modifying. That last one is subtle but important: if an AI agent is writing code that touches a service, it should understand that service&rsquo;s actual runtime behavior, not just its source code.\n\n**Dynatrace** and **DevCycle** partnered to make feature flags observable primitives via [OpenFeature](https://github.com/open-feature/spec). Rolling out AI features behind feature flags is table stakes, but having those flags show up in your observability pipeline as first-class signals closes a real gap.\n\nShadow AI governance emerged as its own theme. **CAST AI&rsquo;s Kimchi** can route requests across 50+ models while providing centralized visibility into what models are being used, by whom, and at what cost. Every large organization I talked to had some version of the same problem: teams spinning up model endpoints without central oversight, burning through GPU budgets, creating compliance blind spots they did not even know about.\n\nGPU multi-tenancy remains genuinely unsolved. Scheduling, workload isolation, cost attribution across shared GPUs — all of it breaks down at scale. Multiple talks addressed pieces of this, but nobody had a complete answer.\n\n## Sovereignty shapes infrastructure architecture\n\nRegulation came up in almost every conversation. The EU Cyber Resilience Act is driving compliance requirements deep into software supply chains, and every European organization I spoke with is feeling the pressure. Teams are already changing how they build and deploy software.\n\nSovereign Kubernetes is a platform architecture requirement now, not something you can defer to next quarter. Organizations need Kubernetes distributions and cloud regions that guarantee data residency, and they need the tooling to enforce those guarantees programmatically. Self-hosted models are proliferating partly because of capability and cost, but data sovereignty is the accelerant. If your data cannot leave a jurisdiction, neither can your model.\n\nRuntime isolation is expanding beyond containers. Several talks covered KVM-based isolation for AI workloads, which is heavier than containers but necessary when the threat model includes side-channel attacks on shared GPU memory. The sandboxing conversation has gotten more sophisticated since last year.\n\nThese constraints are not uniquely European. Any organization operating across jurisdictions faces similar pressures, and the regulatory direction globally is toward more data sovereignty requirements, not fewer.\n\n![The KubeCon EU 2026 show floor at the RAI Convention Centre in Amsterdam](showroom.jpg)\n\n## What this means for your team\n\nFour days in Amsterdam distilled into five things I would act on now:\n\n- \n\n**Treat inference workloads like production services.** If you are still deploying models with scripts and hope, stop. Inference infrastructure needs the same IaC discipline as any other production system: version-controlled, tested, policy-enforced.\n\n- \n\n**Evaluate the [Gateway API Inference Extension](https://github.com/kubernetes-sigs/gateway-api-inference-extension) and [llm-d](https://github.com/llm-d/llm-d).** These are not speculative projects. They have broad industry backing and solve real problems around inference routing and distributed serving. Get them into your test environments.\n\n- \n\n**Plan agent identity before agents proliferate.** [SPIFFE/SPIRE](https://github.com/spiffe/spire) for agent identity is not optional if you are running agents in production. Retrofitting identity onto an existing agent fleet is painful. Start with [kagenti](https://github.com/kagenti/kagenti) now.\n\n- \n\n**Platform teams should own AI infrastructure.** Shadow AI is already happening in your organization. The platform engineering team needs to provide self-service AI infrastructure with guardrails before ungoverned model endpoints become a security and cost problem.\n\n- \n\n**Sovereignty and GPU multi-tenancy are universal.** Even if you are not subject to the EU Cyber Resilience Act today, data residency requirements are spreading globally. GPU multi-tenancy will affect every organization running inference at scale.\n\nKubernetes spent the past decade proving it could orchestrate containers. The next decade will test whether it can orchestrate intelligence. Based on what I saw in Amsterdam, the community is building the right pieces, but the gap between what exists and what production demands is still wide. That gap is where the interesting work happens.","publishedAt":"2026-04-01T07:00:00.000Z","url":"https://www.pulumi.com/blog/kubecon-eu-2026-recap/","media":[]},{"id":"rel_iprvX_KaP1OZUy6DIuJiR","version":null,"title":"Introducing OTel Tracing in the Pulumi CLI","summary":"![](https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/meta.png)\n\nTracing is an important part of our CLI observability story. So ...","content":"![](https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/meta.png)\n\nTracing is an important part of our CLI observability story. So far we&rsquo;ve relied on (the now deprecated) [OpenTracing](https://opentracing.io/) 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.\n\n## Background\n\nWe introduced tracing using [OpenTracing](https://opentracing.io) [all the way back in 2017](https://github.com/pulumi/pulumi/pull/521), before [OpenTelemetry](https://opentelemetry.io/) 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&rsquo;d either have to enhance our current OpenTracing setup, or do the work to switch to OTel.\n\nIn 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.\n\n## Enter OTel\n\nWith 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&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.\n\nGiven 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 [gRPC](https://grpc.io/), and the CLI will do any further processing. This means only one process will write to the file, if requested.\n\nFor 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.\n\n## Try it out\n\nCurrently 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 `--otel-traces |grpc://>` flag, using pulumi version v3.226 or newer. For further documentation see [our performance tracing docs](https://www.pulumi.com/docs/support/debugging/performance-tracing/#opentelemetry-tracing).\n\nTo view the traces, you can use one of the various exporters that exist. Popular options include [Jaeger](https://www.jaegertracing.io/), [OTel Desktop Viewer](https://github.com/CtrlSpice/otel-desktop-viewer), or [OTel TUI](https://github.com/ymtdzzz/otel-tui) if you prefer not leaving your terminal. Once you&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 `pulumi-cli: pulumi` root span.\n\nAll 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.\n\nAs always, we would love any feedback either in the [Community Slack](https://slack.pulumi.com/), or through a [GitHub issue](https://github.com/pulumi/pulumi/issues).","publishedAt":"2026-04-01T00:00:00.000Z","url":"https://www.pulumi.com/blog/introducing-otel-tracing-in-the-pulumi-cli/","media":[]},{"id":"rel_V8ZVeS3gAeV0TP0TZM2lL","version":null,"title":"Introducing Read-Only Mode for Pulumi Neo","summary":"![](https://www.pulumi.com/blog/neo-read-only-mode/meta.png)\n\nA platform engineer with broad access might want Neo to analyze infrastructure and sugge...","content":"![](https://www.pulumi.com/blog/neo-read-only-mode/meta.png)\n\nA platform engineer with broad access might want Neo to analyze infrastructure and suggest changes, but include guarantees it won&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.\n\n## Control what Neo can change\n\nNeo 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&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.\n\n## How it works\n\nWhen you create a Neo task, you now choose between two permission levels:\n\nOption\nWhat Neo can do\nAvailability\n\n**Use my permissions**\nFull access (current default behavior)\nAll tiers\n\n**Read-only**\nRead, preview, and create PRs. No infrastructure mutations.\nAll tiers\n\nRead-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&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.\n\n## Read-only mode and auto-approve\n\nNeo&rsquo;s [operating modes](https://www.pulumi.com/docs/ai/tasks/#task-modes) 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.\n\nRead-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.\n\n## Getting started\n\nRead-only mode is available today for all Pulumi Cloud users.\n\n- [Sign in to Pulumi Cloud](https://app.pulumi.com/signin) and select **Read-only** when creating your next Neo task\n\n- [Read the Neo documentation](https://www.pulumi.com/docs/ai/) for detailed guides on permission levels\n\n- [Join the Community Slack](https://slack.pulumi.com/) to share your feedback","publishedAt":"2026-04-01T00:00:00.000Z","url":"https://www.pulumi.com/blog/neo-read-only-mode/","media":[]},{"id":"rel_9s7X1hWIT2yoxmJOiRuHi","version":null,"title":"Neo Plan Mode: Iterate Before You Execute","summary":"![](https://www.pulumi.com/blog/neo-plan-mode/meta.png)\n\nInfrastructure work ranges from simple updates to complex multi-stack operations. For straigh...","content":"![](https://www.pulumi.com/blog/neo-plan-mode/meta.png)\n\nInfrastructure 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&rsquo;re launching Plan Mode, a dedicated experience for collaborating with Neo on a detailed plan before execution begins.\n\n## Plan Mode\n\nWithout 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.\n\n## How it works\n\nEnter Plan Mode by selecting the plan button when starting a task. Neo shifts its behavior:\n\n- **Discovery**: Neo investigates your environment — examining existing infrastructure, reading relevant code, checking dependencies, and researching patterns.\n\n- **Synthesis**: 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.\n\n- **Refinement**: You refine the plan through normal conversation, challenging assumptions, asking for an alternative approach, or requesting more detail on a specific area.\n\n- **Approval**: Once you&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.\n\n## When to use it\n\nPlan Mode is opt-in. You choose it when you want to work through an approach before committing:\n\n- **Complex multi-stack operations** where understanding dependencies matters\n\n- **Unfamiliar infrastructure** where discovery reduces churn\n\n- **Autonomous execution** where plan approval is your key control point before Neo runs without step-by-step oversight\n\n## Get started\n\nPlan Mode is available now for all Pulumi Cloud organizations. It works with any [task mode](https://www.pulumi.com/docs/ai/tasks/#task-modes), so you can pair thorough upfront planning with whatever level of execution autonomy fits the situation.\n\nTo try it, [open Neo in Pulumi Cloud](https://app.pulumi.com/neo). For more details, see the [Plan Mode documentation](https://www.pulumi.com/docs/ai/tasks/#plan-mode).","publishedAt":"2026-04-01T00:00:00.000Z","url":"https://www.pulumi.com/blog/neo-plan-mode/","media":[]},{"id":"rel_GdhazjSSYGCdtuny6zk7l","version":null,"title":"How We Eliminated Long-Lived CI Secrets Across 70+ Repos","summary":"![](https://www.pulumi.com/blog/eliminating-ci-secrets-with-pulumi-esc/meta.png)\n\nSupply chain attacks on CI/CD pipelines are accelerating. A growing ...","content":"![](https://www.pulumi.com/blog/eliminating-ci-secrets-with-pulumi-esc/meta.png)\n\nSupply chain attacks on CI/CD pipelines are accelerating. A growing pattern involves attackers compromising popular [GitHub Actions](https://github.com/features/actions) through *tag poisoning* — rewriting trusted version tags to point to malicious code that harvests environment variables, cloud credentials, and API tokens from runner environments. The stolen credentials are then exfiltrated to attacker-controlled infrastructure, often before anyone notices.\n\nFor every engineering organization, the question is no longer *if* your CI pipeline will encounter a compromised dependency, but *what is exposed when it does*.\n\nAt Pulumi, we asked ourselves that question and decided the answer should be &ldquo;nothing useful.&rdquo; Here&rsquo;s how we got there.\n\n## The problem with static CI secrets\n\nMost organizations store long-lived cloud credentials, API tokens, and service account keys as GitHub repository or organization secrets. But this approach has several well-known problems:\n\n- **Broad availability.** Every workflow run on a repository can access every secret stored in that repo. A compromised action in any workflow can read them all.\n\n- **No expiration.** Secrets persist until someone manually rotates them. If exfiltrated, they give attackers persistent access for weeks or months.\n\n- **No granular audit trail.** GitHub tells you a secret was used, but not which workflow, which step, or what it was used for.\n\n- **Secret sprawl.** Across dozens or hundreds of repos, the same credentials are often duplicated, making rotation a coordinated, error-prone effort.\n\nIn a supply chain attack scenario, this is exactly what attackers count on: a single compromised action that can dump a trove of long-lived credentials.\n\n## Our approach: zero static secrets\n\nWe replaced every static GitHub Secret across our CI pipelines with short-lived, dynamically fetched credentials using [Pulumi ESC](https://www.pulumi.com/docs/esc/) and [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/). The credential flow works in layers, each scoped and ephemeral:\n\n- **GitHub generates a short-lived OIDC token** scoped to the specific workflow run, repository, and branch. This token is cryptographically signed by GitHub&rsquo;s OIDC provider.\n\n- **The token is exchanged with Pulumi Cloud** for a short-lived Pulumi access token. Pulumi Cloud validates the OIDC claims (organization, repository, branch) against a configured trust policy before issuing the token.\n\n- **The Pulumi access token opens an ESC environment** to retrieve the credentials the workflow needs — cloud provider keys, API tokens, or other secrets.\n\n- **Cloud credentials themselves are dynamic.** ESC environments use [OIDC login providers](https://www.pulumi.com/docs/esc/guides/configuring-oidc/) to fetch short-lived credentials directly from AWS, Azure, or GCP. No static keys or cloud credentials are stored anywhere.\n\nThe [`pulumi/esc-action`](https://github.com/marketplace/actions/esc-action) GitHub Action handles this entire flow in a single workflow step.\n\nsequenceDiagram\nparticipant Runner as GitHub Actions Runner\nparticipant GH as GitHub OIDC Provider\nparticipant PC as Pulumi Cloud\nparticipant ESC as Pulumi ESC\nparticipant Cloud as Cloud Provider (AWS/Azure/GCP)\nRunner->>GH: Request OIDC token (scoped to workflow run)\nGH-->>Runner: Short-lived JWT\nRunner->>PC: Exchange JWT for Pulumi access token\nPC-->>Runner: Short-lived access token\nRunner->>ESC: Open environment with access token\nESC->>Cloud: OIDC login (assume role / federated identity)\nCloud-->>ESC: Short-lived cloud credentials\nESC-->>Runner: Cloud credentials + secrets\nNote over Runner,Cloud: Nothing is stored. Everything expires.\n\n## What the change looks like\n\nBefore this migration, our workflows referenced static secrets stored in GitHub:\n\n```\nenv:\n AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n\n```\n\nAfter the migration, an [ESC environment](https://www.pulumi.com/docs/esc/environments/) handles credential fetching via OIDC. Here is what the environment definition looks like:\n\n```\nvalues:\n aws:\n login:\n fn::open::aws-login:\n oidc:\n duration: 1h\n roleArn: arn:aws:iam::123456789012:role/pulumi-esc-role\n sessionName: esc-${context.pulumi.user.login}\n # Optional: scope down the session beyond what the role allows\n policyArns:\n - arn:aws:iam::123456789012:policy/ci-build-minimal\n environmentVariables:\n AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}\n AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}\n\n```\n\nThe `roleArn` and optional [`policyArns`](https://www.pulumi.com/docs/esc/integrations/dynamic-login-credentials/aws-login/) make least-privilege straightforward: each login provider assumes a specific role, and `policyArns` can scope the session down further. You can use multiple login providers in one environment or separate environments per workflow to match permissions to each job&rsquo;s needs.\n\nThe workflow itself becomes minimal — a single step that authenticates via OIDC and injects the credentials:\n\n```\npermissions:\n contents: read\n id-token: write  # Required for OIDC\n\nsteps:\n - name: Fetch secrets from ESC\n uses: pulumi/esc-action@v1\n with:\n environment: '/'\n\n```\n\nThe static `secrets.*` references are gone entirely. Every credential is fetched at runtime through ESC.\n\n## Scale: 70+ repos, zero static secrets\n\nWe didn&rsquo;t do this for one or two flagship repos; we rolled it out across **every Pulumi provider repository**: AWS, Azure, GCP, Kubernetes, and over 60 more. The migration was managed centrally through our [`ci-mgmt`](https://github.com/pulumi/ci-mgmt) tooling, which generates consistent workflow configurations across all provider repos.\n\nThe pattern is the same everywhere:\n\n- Each repo has a corresponding ESC environment under a `github-secrets/` project.\n\n- All workflow-level `${{ secrets.* }}` references have been removed.\n\n- The `pulumi/esc-action` step with OIDC auth is the single entry point for all credentials.\n\nWhen every repo follows the same pattern like this, security posture is much more easily verifiable and auditable.\n\n## Auditability and centralized control\n\nBeyond eliminating static secrets, this migration gave us centralized visibility and control that GitHub Secrets cannot provide:\n\n- **[Audit logging](https://www.pulumi.com/docs/esc/administration/audit-logs/).** ESC records which credentials were accessed, when, and by which workflow. This is a meaningful improvement over GitHub&rsquo;s binary &ldquo;secret was used&rdquo; signal.\n\n- **Centralized access policies.** Access rules are defined once in ESC rather than scattered across individual repository settings pages.\n\n- **Single-point rotation.** Because ESC environments can [import other environments](https://www.pulumi.com/docs/esc/environments/imports/), shared credentials live in a common base that all 70+ repo environments are composed of. Update it once, and every repo picks up the change on its next run.\n\n- **Dynamic credentials by default.** For cloud providers like AWS, Azure, and GCP, ESC fetches credentials via OIDC at open time. There is nothing to rotate because nothing is stored.\n\n## What happens if a GitHub Action is compromised\n\nWith this architecture in place, here is what an attacker gets if a compromised GitHub Action runs in our CI:\n\n- **No GitHub Secrets to dump.** The repository settings page has no stored secrets for a malicious action to exfiltrate.\n\n- **OIDC tokens are scoped and short-lived.** The GitHub-issued JWT is valid only for the specific workflow run and expires within minutes.\n\n- **Cloud credentials are ephemeral.** Any AWS, Azure, or GCP credentials fetched through ESC are short-lived and scoped to the role assumed during that run.\n\n- **No persistent access.** There are no long-lived tokens to reuse hours or days later.\n\nCompare this to the traditional model, where a single compromised action could exfiltrate AWS access keys that remain valid until someone manually rotates them — which could be weeks or months.\n\nThe goal is not to prevent every possible attack. It is to make the blast radius as small as possible when something goes wrong.\n\n## Get started\n\nIf you want to adopt the same pattern in your own CI pipelines:\n\n- [**Tutorial: Using ESC with GitHub Actions**](https://www.pulumi.com/tutorials/esc-github/) — Step-by-step setup guide.\n\n- [**Announcing the Pulumi ESC GitHub Action**](https://www.pulumi.com/blog/announcing-pulumi-esc-github-action/) — Full feature overview and capabilities.\n\n- [**Configuring OIDC for ESC**](https://www.pulumi.com/docs/esc/guides/configuring-oidc/) — Set up OIDC trust between ESC and your cloud providers.\n\n- [**Pulumi ESC documentation**](https://www.pulumi.com/docs/esc/) — Full documentation for environments, secrets, and configuration.\n\nYour CI secrets do not have to be a liability. With OIDC and Pulumi ESC, they do not have to exist at all.","publishedAt":"2026-03-31T00:00:00.000Z","url":"https://www.pulumi.com/blog/eliminating-ci-secrets-with-pulumi-esc/","media":[]},{"id":"rel_BHWxR_T9Q_GKNeJX2Ifvp","version":null,"title":"Pulumi IAM Expands: Manage Access at Scale with Tags, Roles, and Teams","summary":"![](https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/meta.png)\n\nSince the launch of [Pulumi IAM](https://www.pulumi.com/blog/pulumi...","content":"![](https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/meta.png)\n\nSince the launch of [Pulumi IAM](https://www.pulumi.com/blog/pulumi-cloud-iam-launch/) with [custom roles](https://www.pulumi.com/docs/administration/access-identity/rbac/roles/) and scoped [access tokens](https://www.pulumi.com/docs/administration/access-identity/access-tokens/), 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.\n\nToday, we&rsquo;re introducing three new capabilities to help you manage permissions more dynamically at scale: **tag-based access control**, **team role assignments**, and **user role assignments**.\n\n## Why tag-based access control?\n\nWith custom roles, you can define granular permissions using [fine-grained scopes](https://www.pulumi.com/docs/administration/access-identity/rbac/scopes). 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.\n\n## What&rsquo;s new?\n\n### Tag-based access control\n\nYou 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 `env:prod`, anyone with a role containing a matching tag-based rule automatically gets the right permissions. No manual assignment required.\n\nA single role can include multiple tag-based rules, and they are evaluated with **OR** 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 **AND** logic for precise targeting. For example, a rule with conditions `env:prod` and `team:payments` ensures access is granted only to production resources owned by the payments team.\n\n### Team role assignments\n\nCustom roles can now be assigned directly to [teams](https://www.pulumi.com/docs/administration/access-identity/rbac/teams) within your Pulumi organization. When an engineer joins a team, whether manually or via [SCIM provisioning](https://www.pulumi.com/docs/pulumi-cloud/access-management/scim/), they automatically inherit the permissions defined in the team&rsquo;s assigned roles.\n\nTeams support both **inline permissions** (ad-hoc access to specific stacks, environments, or accounts) and **role-based permissions** simultaneously. You can assign **multiple roles** 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.\n\n**\n\nTeam admins (or users with the `team:update` scope) can continue to manage their team&rsquo;s inline permissions as they do today. However, assigning organization-level custom roles to a team requires additional permissions: `role:read` and `role:update`.\n\n### User role assignments\n\nCustom 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 `Admin`, `Member`, and `Billing Manager` [roles](https://www.pulumi.com/docs/administration/access-identity/rbac/roles).\n\n### How permissions work together\n\nPermissions in Pulumi IAM are **additive**. 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 &ldquo;SRE&rdquo; and &ldquo;Security&rdquo; teams inherits permissions from both team roles, plus any role assigned to them individually.\n\n## How to get started\n\nConfiguring tag-based access control and role assignments is done through the Pulumi Cloud console and REST API.\n\n### 1. Create a custom role with tag-based rules\n\nIn Pulumi Cloud, navigate to **Settings** > **Access Management** > **Roles** and create a new custom role. In the role configuration, add tag-based rules that define which entities the role should apply to.\n\nFor example, to create a role that grants write access to all production stacks:\n\n- Click **Create custom role** and give it a descriptive name (e.g., &ldquo;Production Deployer&rdquo;)\n\n- Add a permission set (e.g., Stack Write) to the role\n\n- Under entity selection, choose **Tag-based rule**\n\n- Set the condition: tag key `env` equals `prod`\n\n- Save the role\n\n### 2. Assign the role to a team\n\nGo to **Settings** > **Access Management** > **Teams**, select a team, and assign your custom role. All team members immediately inherit the defined permissions.\n\n### 3. Assign a role to an individual user\n\nFor users with unique access requirements, go to **Settings** > **Access Management** > **Members**, select a user, and assign a custom role directly.\n\n[Video](abac-demo.mp4)\n\n## Enforce tagging standards with Pulumi Policy\n\nTag-based access control relies on consistent tagging. If a stack is missing a tag or has an incorrect value, permissions won&rsquo;t be applied as expected. [Pulumi Policy](https://www.pulumi.com/docs/insights/policy/) closes this gap by letting you enforce tagging standards as a [preventative policy group](https://www.pulumi.com/docs/insights/policy/policy-groups/), so any `pulumi up` 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.\n\nTo learn how to write policies that validate stack tags, see [Using stack tags in policies](https://www.pulumi.com/docs/insights/policy/policy-packs/authoring/#using-stack-tags-in-policies).\n\n**\n\nPulumi 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.\n\n## Availability\n\nTag-based access control, team role assignments, and user role assignments are available today for customers on the **Pulumi Enterprise** and **Pulumi Business Critical** plans. Check out our [pricing page](https://www.pulumi.com/pricing/) for more details on editions and what&rsquo;s included.\n\n## Conclusion\n\nWith 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&rsquo;re excited to see how you leverage these new capabilities to secure and streamline your cloud operations.\n\nExplore the [IAM documentation](https://www.pulumi.com/docs/administration/access-identity/rbac) to get started, and share your feedback in our [GitHub repository](https://github.com/pulumi/pulumi-cloud-requests/issues).\n\n## Learn more\n\n- [RBAC overview](https://www.pulumi.com/docs/administration/access-identity/rbac)\n\n- [Roles](https://www.pulumi.com/docs/administration/access-identity/rbac/roles)\n\n- [Permission sets](https://www.pulumi.com/docs/administration/access-identity/rbac/permission-sets)\n\n- [Teams](https://www.pulumi.com/docs/administration/access-identity/rbac/teams)\n\n- [Scopes](https://www.pulumi.com/docs/administration/access-identity/rbac/scopes)\n\n- [Pulumi IAM launch blog](https://www.pulumi.com/blog/pulumi-cloud-iam-launch/)\n\n- [Pulumi IAM for self-hosted](https://www.pulumi.com/blog/pulumi-cloud-iam-self-hosted/)","publishedAt":"2026-03-19T17:30:00.000Z","url":"https://www.pulumi.com/blog/expanding-pulumi-iam-custom-permissions/","media":[]},{"id":"rel_hlJzjJvFtea5e2p46eNau","version":null,"title":"From Kubernetes Gatekeeper to Full-Stack Governance with OPA","summary":"![](https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/meta.png)\n\nPulumi&rsquo;s [OPA (Open Policy Agent)](https://www.openpo...","content":"![](https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/meta.png)\n\nPulumi&rsquo;s [OPA (Open Policy Agent)](https://www.openpolicyagent.org/) support is now stable. The [v1.1.0 release](https://github.com/pulumi/pulumi-policy-opa/releases/tag/v1.1.0) of `pulumi-policy-opa` 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 [Kubernetes Gatekeeper](https://open-policy-agent.github.io/gatekeeper/) constraint templates, a new compatibility mode lets you drop those `.rego` files directly into a Pulumi policy pack and enforce them against your Kubernetes resources without modification.\n\n## What&rsquo;s in the stable release\n\nOPA/Rego is now fully supported as a policy language for [Pulumi Insights](https://www.pulumi.com/docs/insights/policy/), with the same capabilities as the TypeScript and Python SDKs:\n\n- **Resource and stack-level policies**: Validate individual resources with `deny` and `warn` rules, or evaluate your entire stack at once with `stack_deny` and `stack_warn` for cross-resource checks like relationship validation and resource count limits.\n\n- **Enforcement levels**: Control how violations are handled. `mandatory` blocks deployments, `advisory` surfaces warnings, and `disabled` turns rules off without removing them. Enforcement levels can be overridden per policy without modifying Rego source.\n\n- **Policy configuration**: Pass custom parameters to policies via configuration files, with optional JSON schema validation. Configuration values are accessible in Rego as `data.config..`.\n\n- **OPA metadata annotations**: Use standard OPA `# METADATA` comments to provide titles, descriptions, and messages for your policies. These populate the policy metadata displayed in Pulumi Cloud.\n\n- **Preventative and audit evaluation**: OPA policies work with both [preventative enforcement](https://www.pulumi.com/docs/insights/policy/) during `pulumi up` and [audit policy scans](https://www.pulumi.com/blog/policy-audit-scans-for-stacks/) for continuous compliance monitoring.\n\nYou 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 [policy groups](https://www.pulumi.com/docs/insights/policy/policy-groups/).\n\n## Kubernetes Gatekeeper compatibility\n\nThe headline feature of this release is native support for [Kubernetes Gatekeeper](https://open-policy-agent.github.io/gatekeeper/) constraint template rules. If you&rsquo;re running Gatekeeper as an admission controller in your clusters, you likely have a library of `.rego` 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 `pulumi preview` before resources ever reach the cluster.\n\nTo enable Gatekeeper compatibility, set `inputFormat: kubernetes-admission` in your `PulumiPolicy.yaml`:\n\n```\ndescription: Kubernetes Gatekeeper Policy Pack\nruntime: opa\ninputFormat: kubernetes-admission\n\n```\n\nWith this setting, Pulumi automatically wraps Kubernetes resources in the Gatekeeper [AdmissionReview](https://open-policy-agent.github.io/gatekeeper/website/docs/howto) structure (`input.review.object`, `input.review.kind`, etc.), so your existing rules work without modification. Non-Kubernetes resources are silently skipped.\n\nHere&rsquo;s an example that reuses standard Gatekeeper-style rules, requiring an `app` label and prohibiting the `latest` image tag:\n\n```\npackage gatekeeper\n\nimport rego.v1\n\n# METADATA\n# title: Require App Label\n# description: All Kubernetes resources must have an \"app\" label.\nviolation contains {\"msg\": msg} if {\n not input.review.object.metadata.labels[\"app\"]\n msg := sprintf(\"%s '%s' is missing required label: app\",\n [input.review.kind.kind, input.review.name])\n}\n\n# METADATA\n# title: Disallow Latest Tag\n# description: Container images must not use the \"latest\" tag.\ndeny contains msg if {\n container := input.review.object.spec.template.spec.containers[_]\n endswith(container.image, \":latest\")\n msg := sprintf(\"container '%s' uses the 'latest' tag -- pin to a specific version\",\n [container.name])\n}\n\n```\n\nThese rules are identical to what you&rsquo;d write for Gatekeeper. Both rule head formats are supported and can coexist: the `violation[{\"msg\": msg}]` map format and the `deny[msg]` string format. Per-policy configuration via `input.parameters` also works as expected. You can take a `.rego` 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.\n\nThis shifts policy enforcement left. Instead of waiting for the Kubernetes API server to reject a resource at admission time, you catch the violation during `pulumi preview`, before anything is deployed.\n\n## Walkthrough: Reusing policies from the gatekeeper-library\n\nThe [OPA Gatekeeper Library](https://github.com/open-policy-agent/gatekeeper-library) 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&rsquo;s an end-to-end example using the [`allowedrepos`](https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/allowedrepos) policy to restrict which container image registries your deployments can use.\n\n- \n\nCreate a new Kubernetes OPA policy pack:\n\n```\npulumi policy new kubernetes-opa\n\n```\n\n- \n\nCopy the Rego source from [gatekeeper-library](https://github.com/open-policy-agent/gatekeeper-library/blob/master/library/general/allowedrepos/template.yaml) into your policy pack as `allowedrepos.rego`. No modifications are needed:\n\n```\npackage k8sallowedrepos\n\nviolation[{\"msg\": msg}] {\n container := input.review.object.spec.containers[_]\n not strings.any_prefix_match(container.image, input.parameters.repos)\n msg := sprintf(\"container  has an invalid image repo , allowed repos are %v\",\n [container.name, container.image, input.parameters.repos])\n}\n\nviolation[{\"msg\": msg}] {\n container := input.review.object.spec.initContainers[_]\n not strings.any_prefix_match(container.image, input.parameters.repos)\n msg := sprintf(\"initContainer  has an invalid image repo , allowed repos are %v\",\n [container.name, container.image, input.parameters.repos])\n}\n\nviolation[{\"msg\": msg}] {\n container := input.review.object.spec.ephemeralContainers[_]\n not strings.any_prefix_match(container.image, input.parameters.repos)\n msg := sprintf(\"ephemeralContainer  has an invalid image repo , allowed repos are %v\",\n [container.name, container.image, input.parameters.repos])\n}\n\n```\n\n- \n\nVerify that your `PulumiPolicy.yaml` has Gatekeeper compatibility enabled:\n\n```\ndescription: Kubernetes Gatekeeper Policy Pack\nruntime: opa\ninputFormat: kubernetes-admission\n\n```\n\n- \n\nConfigure the allowed registries. Create a `policy-config.json` file to pass the `repos` parameter:\n\n```\n{\n \"k8sallowedrepos\": {\n \"repos\": [\"gcr.io/my-company/\", \"docker.io/library/\"]\n }\n}\n\n```\n\n- \n\nTest the policy locally against a stack:\n\n```\npulumi preview --policy-pack . --policy-pack-config policy-config.json\n\n```\n\nAny Kubernetes deployment using an image outside the allowed registries will produce a violation at preview time, before it reaches the cluster.\n\n- \n\nPublish the pack and add it to a [policy group](https://www.pulumi.com/docs/insights/policy/policy-groups/) to enforce it across your organization:\n\n```\npulumi policy publish\n\n```\n\nThe same approach works for any policy in the gatekeeper-library: [`containerlimits`](https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/containerlimits), [`requiredlabels`](https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/requiredlabels), [`disallowedtags`](https://github.com/open-policy-agent/gatekeeper-library/tree/master/library/general/disallowedtags), and others. Copy the Rego, configure parameters, and publish.\n\n## Part of the Pulumi Insights governance story\n\nOPA policy support is part of the broader [Pulumi Insights](https://www.pulumi.com/docs/insights/) governance platform. Insights gives you visibility and compliance across your entire cloud footprint, and OPA policies plug directly into that:\n\n- **Audit policy scans** continuously evaluate OPA policies against your [Pulumi stacks](https://www.pulumi.com/blog/policy-audit-scans-for-stacks/) and discovered cloud resources, providing a compliance baseline without redeploying anything.\n\n- **Self-hosted execution** lets you [run policy evaluations on your own infrastructure](https://www.pulumi.com/blog/self-hosted-insights/) using customer-managed workflow runners, keeping credentials and data within your network.\n\n- **Pre-built compliance packs** for CIS, NIST, PCI DSS, and other frameworks are available alongside your custom OPA policies in the same [policy groups](https://www.pulumi.com/docs/insights/policy/policy-groups/).\n\nWhether you&rsquo;re enforcing policy at deployment time, scanning existing infrastructure for drift, or running continuous compliance checks, OPA policies are a native participant.\n\n![Policy Findings dashboard in Pulumi Cloud showing compliance scores and per-stack policy evaluation results](policy-findings.png)\n\n## Frequently asked questions\n\n### Do I need to modify my existing Gatekeeper `.rego` files?\n\nNo. Set `inputFormat: kubernetes-admission` in your `PulumiPolicy.yaml` and your existing Gatekeeper constraint template rules work as-is. Pulumi handles the AdmissionReview wrapping automatically.\n\n### What happens with non-Kubernetes resources?\n\nWhen using `inputFormat: kubernetes-admission`, non-Kubernetes resources are silently skipped during evaluation. Your Gatekeeper rules only run against Kubernetes resources.\n\n### Do I need OPA installed locally?\n\nNo. The `pulumi-policy-opa` 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 `opa test` against your policies independently.\n\n### When should I use OPA vs. TypeScript or Python for policies?\n\nIf 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.\n\nGatekeeper constraint templates can be reused directly via the `kubernetes-admission` input format, but other OPA integrations use different input structures, so those policies would need to be adapted to Pulumi&rsquo;s resource model. All three languages work together in the same policy groups.\n\n## Get started\n\nTemplates are available for `kubernetes-opa`, `aws-opa`, `azure-opa`, and `gcp-opa` via `pulumi policy new`. For more details, see the [policy authoring guide](https://www.pulumi.com/docs/insights/policy/policy-packs/authoring/) and the [Policy as Code overview](https://www.pulumi.com/docs/insights/policy/).\n\n[\nGet started with OPA policies\n](https://www.pulumi.com/docs/insights/policy/)\n[\n![GitHub repository: pulumi/pulumi-policy-opa](https://opengraph.githubassets.com/1/pulumi/pulumi-policy-opa)\n\n**\ngithub.com/pulumi/pulumi-policy-opa\n\n](https://github.com/pulumi/pulumi-policy-opa)","publishedAt":"2026-03-19T00:00:00.000Z","url":"https://www.pulumi.com/blog/kubernetes-gatekeeper-full-stack-governance-opa/","media":[]},{"id":"rel_LX9a9MhVsQjaRp-FmIDWt","version":null,"title":"Lock Down Values in Pulumi ESC with fn::final","summary":"![](https://www.pulumi.com/blog/esc-fn-final/meta.png)\n\n[Pulumi ESC (Environments, Secrets, and Configuration)](https://www.pulumi.com/docs/esc/) allo...","content":"![](https://www.pulumi.com/blog/esc-fn-final/meta.png)\n\n[Pulumi ESC (Environments, Secrets, and Configuration)](https://www.pulumi.com/docs/esc/) 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 [fn::final](https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/) 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.\n\n## How it works\n\nLet&rsquo;s say you have a parent environment that sets the AWS region for all deployments. You can use `fn::final` to ensure no child environment can change it:\n\n```\n# project/parent-env\nvalues:\n aws-region:\n fn::final: us-east-1\n\n```\n\nIf a child environment tries to override the final value, ESC raises a `cannot override final value` warning.\n\n```\n# project/child-env\nimports:\n - project/parent-env\nvalues:\n aws-region: eu-west-1 # raises a warning\n\n```\n\nThis evaluates to:\n\n```\n{\n \"aws-region\": \"us-east-1\"\n}\n\n```\n\nIn this scenario, the ESC environment is still valid, but the final value remains unchanged.\n\n## When to use fn::final\n\nUse `fn::final` for:\n\n- Security-sensitive values that shouldn&rsquo;t be changed\n\n- Compliance or policy settings enforced by a platform team\n\n- Shared base environments where certain values must remain consistent\n\n## Getting started\n\nThe `fn::final` function is available now in all Pulumi ESC environments. For more information, check out the [fn::final documentation](https://www.pulumi.com/docs/esc/environments/syntax/builtin-functions/fn-final/)!","publishedAt":"2026-03-17T18:00:00.000Z","url":"https://www.pulumi.com/blog/esc-fn-final/","media":[]},{"id":"rel_wOMm6CH9N0xqTbhQr2IG7","version":null,"title":"New: Previous Provider Version Docs in Pulumi Registry","summary":"![](https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/meta.png)\n\nThe [Pulumi Registry](https://www.pulumi.com...","content":"![](https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/meta.png)\n\nThe [Pulumi Registry](https://www.pulumi.com/registry/) now supports browsing documentation for previous versions of first-party Pulumi providers. If you&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 [Pulumi Neo](https://www.pulumi.com/docs/ai) and other agents more accurately assist you with your Pulumi code and operations.\n\n## How it works\n\nWhen you visit a first-party provider&rsquo;s page in the Pulumi Registry, you&rsquo;ll now see a version dropdown selector that lets you switch between the current version and previous versions.\n\n![Version selector dropdown in the Pulumi Registry](registry-version-picker.png)\n\nSelect a previous version from the dropdown, and the Registry loads the full API documentation for that version.\n\n## What&rsquo;s available\n\nThis 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&rsquo;ll be able to view docs for the latest v6.x and v5.x releases in addition to the current version.\n\n## Get started\n\nHead over to the [Pulumi Registry](https://www.pulumi.com/registry/) and try it out. Pick any first-party provider with multiple major versions and use the version dropdown to browse its history.\n\nWe&rsquo;d love to hear your feedback — let us know what you think in the [Pulumi Community Slack](https://slack.pulumi.com) or by opening an issue on [GitHub](https://github.com/pulumi/registry).\n\n[\nExplore the Pulumi Registry\n](https://www.pulumi.com/registry/)","publishedAt":"2026-03-11T00:00:00.000Z","url":"https://www.pulumi.com/blog/previous-version-docs-are-now-available-in-the-pulumi-registry/","media":[]},{"id":"rel_8O51NHUleQqv-26gF5XBZ","version":null,"title":"Pulumi Cloud Now Supports Google Sign-In","summary":"![](https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/meta.png)\n\nMany developers and platform engineers already use Google accounts...","content":"![](https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/meta.png)\n\nMany 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 [GitHub](https://github.com/), [GitLab](https://gitlab.com/), or [Atlassian](https://id.atlassian.com/) account, or an email/password combination. Today, we&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.\n\nAdding Google as an identity provider brings several benefits:\n\n- Use the account you already have. If your team already lives in [Google Workspace](https://workspace.google.com/), you can sign in to Pulumi Cloud with a single click, no new credentials required.\n\n- Inherit your existing security policies. If you&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.\n\n## How it works\n\n### Signing up or signing in\n\nOn the Pulumi Cloud sign-in page, you&rsquo;ll see a new **Sign in with Google** button alongside the existing GitHub, GitLab, and Atlassian options. If you are a new user, select it, authenticate with your Google account, and you&rsquo;re in.\n\n**\n\nIf you already have an existing Pulumi Cloud account, make sure to associate to your existing account as described in the next section.\n\n![Pulumi Cloud sign-in page showing Google as an identity provider option](sign-in.png)\n\n### Connecting Google to an existing account\n\nIf you already have a Pulumi Cloud account, you can link your Google identity from your account settings:\n\n- Navigate to your [Account Settings](https://app.pulumi.com/account/settings).\n\n- Scroll to the **Identity providers** section.\n\n- Under **Available identities**, select **Connect Google**.\n\nOnce connected, you can use Google to sign in to your existing Pulumi Cloud account.\n\n![Account settings showing connected identities including Google](connected-identities.png)\n\n### Google sign-in vs. SAML SSO\n\nGoogle 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.\n\nIf your team uses Google Workspace and needs centralized membership governance for Pulumi Cloud, configure [SAML SSO with Google Workspace](https://www.pulumi.com/docs/administration/access-identity/saml/gsuite/) instead. SAML SSO is available on Pulumi Enterprise and Business Critical editions.\n\n## Get started\n\nGoogle sign-in is available now for all new and existing Pulumi Cloud users:\n\n- **New users**: [Sign up with Google](https://app.pulumi.com/signup) on the Pulumi Cloud sign-up page.\n\n- **Existing users**: [Connect your Google account](https://app.pulumi.com/account/settings) in your account settings.\n\nFor more details, see the [Pulumi Cloud accounts documentation](https://www.pulumi.com/docs/administration/organizations-teams/accounts/).\n\nWe&rsquo;d love to hear your feedback. Join the conversation in the [Pulumi Community Slack](https://slack.pulumi.com) or open an issue on [GitHub](https://github.com/pulumi/pulumi-cloud-requests/issues/new/choose).","publishedAt":"2026-03-10T00:00:00.000Z","url":"https://www.pulumi.com/blog/pulumi-cloud-now-supports-google-sign-in/","media":[]},{"id":"rel_JGIFd1to3hj3ZOj9iV7f_","version":null,"title":"Expanded Version Control Support in Pulumi Cloud","summary":"![](https://www.pulumi.com/blog/expanded-version-control-support/meta.png)\n\nYour version control provider shouldn&rsquo;t limit your infrastructure wo...","content":"![](https://www.pulumi.com/blog/expanded-version-control-support/meta.png)\n\nYour version control provider shouldn&rsquo;t limit your infrastructure workflows. Pulumi Cloud now works with [GitHub](https://www.pulumi.com/docs/version-control/github-app/), [GitHub Enterprise Server](https://www.pulumi.com/docs/version-control/github-app/#github-enterprise-server-support), [Azure DevOps](https://www.pulumi.com/docs/version-control/azure-devops-integration/), and [GitLab](https://www.pulumi.com/docs/version-control/gitlab/). Every team gets the same [deployment pipelines](https://www.pulumi.com/docs/deployments/deployments/), [PR previews](https://www.pulumi.com/docs/deployments/deployments/review-stacks/), and [AI-powered change summaries](https://www.pulumi.com/docs/ai/) regardless of where their code lives.\n\n![Add account screen showing GitHub, GitLab, and Azure DevOps as VCS options](VCS.png)\n\n## Connect multiple providers and accounts\n\nYou 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.\n\n**\n\nGitHub Enterprise Server is currently limited to one connection per Pulumi organization.\n\n## What your team can do\n\n### Deploy on every push\n\nConnect 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.\n\n### Preview changes on pull requests\n\nEvery 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&rsquo;t break anything.\n\n### Neo explains your changes\n\n[Neo](https://www.pulumi.com/product/neo/) posts AI-generated summaries on your pull requests explaining what infrastructure changes mean in plain language. Reviewers who aren&rsquo;t Pulumi experts can still understand the impact of a change without reading resource diffs.\n\n![Neo posting an infrastructure change summary on a pull request](ado-prcomments.png)\n\n### Let Neo open pull requests for you\n\nAsk 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.\n\n### Detect and fix drift\n\nSchedule [drift detection](https://www.pulumi.com/docs/pulumi-cloud/deployments/drift/) 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.\n\n### Secure authentication\n\nPulumi 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.\n\n### Set up new projects from your VCS\n\nThe 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&rsquo;re ready to deploy.\n\n![New project wizard showing repository settings](ado-npw.png)\n\n## Getting started\n\n- An org admin configures the integration under **Settings** > **Version Control**.\n\n- Authorize with your VCS provider.\n\n- Deploy infrastructure with first-class workflows.\n\nFor setup details, see the docs for [GitHub](https://www.pulumi.com/docs/version-control/github-app/), [GitHub Enterprise Server](https://www.pulumi.com/docs/version-control/github-app/#github-enterprise-server-support), [Azure DevOps](https://www.pulumi.com/docs/version-control/azure-devops-integration/), and [GitLab](https://www.pulumi.com/docs/version-control/gitlab/).\n\n[\nConnect your VCS\n**\n](https://app.pulumi.com/signin)","publishedAt":"2026-03-09T00:00:00.000Z","url":"https://www.pulumi.com/blog/expanded-version-control-support/","media":[]},{"id":"rel_mITigqoYKAVEhYiOIJFMH","version":null,"title":"Treating Prompts Like Code: A Content Engineer's AI Workflow","summary":"![](https://www.pulumi.com/blog/treating-prompts-like-code/meta.png)\n\nPulumi has a lot of engineers. It has marketers, solution architects, developer ...","content":"![](https://www.pulumi.com/blog/treating-prompts-like-code/meta.png)\n\nPulumi has a lot of engineers. It has marketers, solution architects, developer advocates. Everyone has something to contribute to docs and blog posts — domain expertise, hard-won lessons, real-world examples. What they don&rsquo;t all have is familiarity with our [Hugo](https://gohugo.io) setup, our style guide, our metadata conventions, or where a new document is supposed to live in the navigation tree. I joined Pulumi in July 2025 as a Senior Technical Content Engineer. A few weeks in, my sole teammate departed. The docs practice was now, functionally, me.\n\nThe problem was clear enough: how do you take one docs engineer&rsquo;s accumulated knowledge and make it available to everyone who needs it, without that engineer becoming a bottleneck?\n\nI started packaging it. Here&rsquo;s what that looked like in practice.\n\n## The real problem AI solves\n\nEveryone talks about AI making you faster. That&rsquo;s not wrong, but it&rsquo;s not the most interesting part — at least not for me.\n\nThe most interesting part is what it does to the *starting* problem. I have an ADHD brain (not formally diagnosed, but with enough self-recognition to know what&rsquo;s going on). I know what that means for my relationship with most tasks: I can see the problem, I understand it, I want to fix it, and then the sheer weight of starting crushes me flat.\n\nWhen I&rsquo;m stuck on a task, the issue is almost never that I don&rsquo;t know what to do. It&rsquo;s that my brain is trying to hold the entire finished product in working memory while simultaneously producing the first step. That&rsquo;s an enormous cognitive tax, and for an ADHD brain it&rsquo;s often insurmountable.\n\nTalking through a problem conversationally is a completely different cognitive load. I can tell [Claude](https://claude.ai) &ldquo;here&rsquo;s the issue, here&rsquo;s what I&rsquo;m trying to accomplish, here&rsquo;s what&rsquo;s weird about it,&rdquo; and suddenly I&rsquo;m not staring at a blank page anymore. I&rsquo;m in a conversation. The scaffold exists. I can build on it.\n\nThat dynamic isn&rsquo;t new for me. In a previous role writing training modules at Microsoft, I did some of my best work, not because the work was easy, but because I had a collaborator. A friend to think out loud with. Someone to say &ldquo;okay, so what are we actually trying to say here?&rdquo; That conversational scaffolding was the difference between spinning and shipping.\n\nIn my current role as a team of one, AI turned out to be that collaborator.\n\nThis isn&rsquo;t really a productivity story. It&rsquo;s closer to a cognitive accommodation story. And I&rsquo;d bet a lot of people — diagnosed or not — will recognize what I&rsquo;m describing.\n\n## Treating prompts like code\n\nIf conversational scaffolding could lower my own activation energy, the next question was obvious: could I build that for anyone who needed it? I knew I wanted to use AI to solve this problem, but I didn&rsquo;t want to just write a bunch of one-off prompts. That would be a maintenance nightmare, and it wouldn&rsquo;t scale beyond me. I needed a system. Claude Code calls these reusable prompts *skills* — other platforms have the same idea under names like plugins or extensions. My first real experiment was `/docs-review` — a reusable prompt that would run my writing through a consistent set of criteria before I committed it. Nothing fancy. I just wanted a reliable bar that didn&rsquo;t depend on my mood or how much coffee I&rsquo;d had.\n\nThen it occurred to me: every PR to our docs repo should get this automatically. So I wired it into our CI/CD pipeline. Meagan, my manager, loved it — and after a few weeks, she noticed that PR quality had improved dramatically. On almost every PR, contributors were now spontaneously pushing an &ldquo;Addressing feedback&rdquo; commit right after the automated review posts — catching and fixing issues before I ever saw the PR.\n\nThat&rsquo;s when something clicked: I wasn&rsquo;t writing prompts anymore. I was writing *modules* — reusable, composable pieces of my own expertise.\n\nThe insight was straightforward, but it changed how I thought about the whole system: if multiple skills need the same context — our style guide, our review criteria, our content standards — that context should live in one place and get consumed by everything that needs it. Just like a shared library. Just like any decent software project.\n\nI created a `REVIEW-CRITERIA.md` file as the single source of truth for what a &ldquo;good&rdquo; docs PR review looks like at Pulumi. Every skill that does any kind of review pulls from it. Change it once, and everything gets smarter at once. Likewise with our style guide, our Hugo conventions, our navigation structure. All of that lives in central reference files that any skill can pull from. If something changes, I change it in one place and all the skills get the update.\n\nThis also matters for token efficiency — which sounds like a nerdy footnote but isn&rsquo;t, especially when automated reviews are running on every PR. Duplicating context across skills bloats token usage fast. Modularizing keeps it lean. Your CI/CD pipeline doesn&rsquo;t care about elegance, but it definitely cares about cost.\n\nThe mental model I kept coming back to: **Don&rsquo;t Repeat Yourself.** It&rsquo;s the same principle that makes good software maintainable. It turns out it makes good AI workflows maintainable too.\n\n## The skill catalog\n\nFrom there, the system grew organically. Whenever I found myself doing something more than once, I asked: &ldquo;Can I turn this into a skill?&rdquo; Here&rsquo;s a sampling of what that produced:\n\n**`/fix-issue`** — takes a [GitHub](https://github.com) issue and recommends a concrete plan of attack, so I go from &ldquo;here&rsquo;s a ticket&rdquo; to &ldquo;here&rsquo;s what I&rsquo;m doing&rdquo; without the spinning-up tax.\n\n**`/shipit`** — runs pre-commit checks, writes a focused commit message, and drafts a PR description.\n\n**`/pr-review`** — full doc review on a PR branch: style guide, code examples, screenshots, optional test deployment, then an Approve/Merge/Request Changes dialog with a drafted comment.\n\n**`/slack-to-issue`** — converts `#docs` [Slack](https://slack.com) conversations into properly formed GitHub issues. Slack is where decisions happen; issues are where work gets tracked.\n\n**`/glow-up`** — runs an older doc through the modern style guide and flags outdated screenshots, for digging out of accumulated technical debt.\n\n**`/new-doc`** and **`/new-blog-post`** — guide anyone through adding a new document or blog post with the right location, metadata, and navigation wiring. Engineers, marketers, whoever. The barrier to contributing just dropped significantly.\n\n**`/docs-tools`** — helps other repo users discover that any of this exists. Discoverability is a real problem with internal tooling.\n\n**\n\nSlack&rsquo;s built-in Claude integration isn&rsquo;t the same Claude running your Claude Code workflows — they don&rsquo;t share context or custom instructions. If you want consistent criteria across both surfaces, you need to bring your own backend. That&rsquo;s exactly what `/slack-to-issue` handles.\n\nOther people started contributing skills to the repo — not because I asked, but because the pattern was legible enough to extend. Someone built a skill for SEO analysis. Marketing added their own review criteria. Engineers contributed workflows I never would have thought to build.\n\nThe thing I&rsquo;d built as a personal survival tool had become a shared platform. That happened because I treated the prompts like code: modular, reusable, documented, open for contribution.\n\n## Honest limitations\n\nIt&rsquo;s not a replacement for human judgment. These are probabilistic tools — they&rsquo;re right most of the time, not all of the time. `/pr-review` doesn&rsquo;t approve PRs autonomously. It highlights things and then asks me, the human, to read them and make the call. The AI does the first pass; I do the last one. That&rsquo;s not a workaround for a limitation — that&rsquo;s the design.\n\nThe system isn&rsquo;t finished, either. It&rsquo;s probably never finished. I&rsquo;m still tweaking review criteria, still finding edge cases where a skill produces something weird, still adding new tools as new pain points emerge. Treating prompts like code means treating them like software: you ship, you iterate, you maintain. There&rsquo;s no version 1.0 and done.\n\nAnd the ADHD angle is real but it&rsquo;s not magic. There are still days where the paralysis wins. AI lowers the activation energy for starting; it doesn&rsquo;t eliminate it. I&rsquo;m still the one who has to show up. I suppose I could automate that too, but then we&rsquo;d be in a whole different kind of dystopia.\n\n## Lessons to share\n\n**Know your models and their costs.** At Pulumi we primarily use Claude, and I work in [Claude Code](https://claude.ai/claude-code); for most tasks I reach for Sonnet rather than Opus. Opus is excellent, but it&rsquo;s significantly more expensive, and well-crafted instructions to Sonnet handle the vast majority of my work just as effectively.\n\n**Treat it like a coworker.** Don&rsquo;t just issue commands and wait for output. Ask what it thinks. Push back when it&rsquo;s wrong. Explain your reasoning. The more you engage conversationally, the better the results tend to be. That extends to alignment, too — before diving into a complex task, talk through the approach first. A few minutes of alignment up front beats iterating on a misunderstood spec. I&rsquo;ve gone as far as adding personal instructions to my config — things like playing along when I&rsquo;m pretending to be Captain Picard, or using colorful language when the context calls for it. (Yes, those are literal config settings.) That sounds frivolous, but it isn&rsquo;t: a tool you actually enjoy using is a tool you&rsquo;ll reach for instead of avoid.\n\n**Modularize your workflow.** Don&rsquo;t write one giant monolithic prompt that tries to do everything. Break it into focused skills that do one thing well and share common context through a central reference file. Easier to maintain, easier to debug, cheaper to run.\n\n**Version control your prompts.** Your skills are code. Treat them like code. Commit them, review them, iterate on them. If a skill starts producing weird output after a tweak, you&rsquo;ll want to know what changed.\n\n**Think about token burn rate.** This matters most when running automation in CI/CD. Keep your skills focused — a skill that checks style doesn&rsquo;t need to load your Hugo navigation conventions. The model only reads what you give it, so give it only what it needs.\n\n**Not everything needs to be a prompt.** This one is underappreciated: skills can include scripts, and that&rsquo;s often the right call. When my team moves a doc in the repo, it needs to happen via `git mv` to preserve history, and we need to add a redirect alias to the front matter to prevent 404s and protect SEO. That&rsquo;s not something I want an AI to reason through from scratch every time — it&rsquo;s a solved problem. So it&rsquo;s a script. The skill just knows the script exists and what it does. Claude orchestrates; the script executes. That&rsquo;s a cleaner, more reliable division of labor than asking an LLM to reinvent the wheel on every run.\n\n**Not everything needs to be generative.** Corollary to the last point: if you need deterministic output, don&rsquo;t use probabilistic tools. We have a skill that generates the meta image for blog posts — procedurally, not generatively. No AI-generated imagery. We have a brand to protect, and &ldquo;let the AI vibe it out&rdquo; isn&rsquo;t a content strategy. The skill follows our visual standards programmatically and produces something consistent every time. Know what you&rsquo;re automating and why.\n\n## What&rsquo;s next\n\nThe next frontier is bringing some of this tooling to the less technical members of the team — marketing, in particular. The skills I&rsquo;ve built assume a certain comfort level with terminals and repos. That&rsquo;s fine for engineers. It&rsquo;s a barrier for everyone else. A friendly interface would lower that bar significantly — that&rsquo;s the direction I&rsquo;m currently exploring.\n\nIf you&rsquo;re a technical writer, a developer advocate, or a solo practitioner figuring out how AI fits into your workflow, the approach described here is a solid starting point. The tools matter, but the mental model matters more: treat your prompts like code. Make them reusable. Document them. Share them.\n\nOur [docs repo](https://github.com/pulumi/docs) is public, so the skills are there for anyone who wants them. If you&rsquo;re building something similar, steal freely — or contribute back.\n\nThe blank page is still there. It&rsquo;s just a lot less intimidating when you&rsquo;ve got a good collaborator and a solid set of tools.\n\n[\nSee our docs skills for inspiration\n**\n](https://github.com/pulumi/docs/tree/master/.claude/commands)","publishedAt":"2026-03-09T00:00:00.000Z","url":"https://www.pulumi.com/blog/treating-prompts-like-code/","media":[]},{"id":"rel_a2m32H2tU_9L2opx_ETwN","version":null,"title":"Now GA: Up to 20x Faster Pulumi Operations for Everyone","summary":"![](https://www.pulumi.com/blog/journaling-ga/meta.png)\n\nIn January, we [introduced a major performance enhancement for Pulumi Cloud](https://www.pulu...","content":"![](https://www.pulumi.com/blog/journaling-ga/meta.png)\n\nIn January, we [introduced a major performance enhancement for Pulumi Cloud](https://www.pulumi.com/blog/journaling/) through a fundamental change to how Pulumi manages state that speeds up operations by up to 20x. After a staged rollout across many organizations, **it is now enabled by default for every Pulumi Cloud operation**. No opt-in required—just use Pulumi CLI v3.225.0+ with Pulumi Cloud. The improvement applies to `pulumi up`, `pulumi destroy`, and `pulumi refresh`; `pulumi preview` does not modify state, so it is unchanged.\n\n## What this means for you\n\nFirst and foremost, nothing about how you work with `pulumi` needs to change. Your updates now benefit from better parallelism and should thus complete faster. Before this change, `pulumi` 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.\n\n## Production results\n\nSince January, we&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.\n\nWe&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&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.\n\nThis 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 [Benchmarks section in the previous blog post](https://www.pulumi.com/blog/journaling/#benchmarks)\n\n## What you need to do\n\nWhile this was an opt-in process using the `PULUMI_ENABLE_JOURNALING` 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.\n\nIf you encounter any issues, reach out on the [Pulumi Community Slack](https://slack.pulumi.com/) or through [Pulumi Support](https://support.pulumi.com/hc/en-us). You can also set the `PULUMI_DISABLE_JOURNALING=true` env variable to opt out of journaling.","publishedAt":"2026-03-05T00:00:00.000Z","url":"https://www.pulumi.com/blog/journaling-ga/","media":[]},{"id":"rel_46JT71uEZ57t5vJMDomq4","version":null,"title":"Now in Public Preview: Store Terraform State in Pulumi Cloud","summary":"![](https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/meta.png)\n\nPlatform engineering teams managing infrastructure across Terraform an...","content":"![](https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/meta.png)\n\nPlatform 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 [Terraform state backend](https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/), 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 [Pulumi Neo](https://www.pulumi.com/docs/ai) — our infrastructure agent — encrypted state storage, update history, state locking, role-based access control, audit policies, and unified resource visibility through [Insights](https://www.pulumi.com/docs/pulumi-cloud/insights/).\n\nThis feature is now available in **public preview**.\n\n## Why this matters\n\nMost 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.\n\nThe 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&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.\n\n## What you get\n\nWhen you store Terraform state in Pulumi Cloud, your Terraform-managed resources get the following added functionality:\n\n**Agentic infrastructure with Neo.** [Neo](https://www.pulumi.com/docs/ai/), Pulumi&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.\n\n**Encrypted state with update history.** State is encrypted in transit and at rest. Every change is tracked as a versioned checkpoint visible in the [stack activity tab](https://www.pulumi.com/docs/deployments/projects-and-stacks/#stack-activity), giving you full rollback capability. This is a common concern for teams currently storing state in S3 buckets.\n\n**Automatic state locking.** Pulumi Cloud prevents concurrent Terraform operations from corrupting state, without requiring you to configure DynamoDB tables or other external locking mechanisms.\n\n**Role-based access control.** Control who can read or modify each stack using [teams and RBAC](https://www.pulumi.com/docs/administration/access-identity/rbac/), applying the same access policies you use for Pulumi stacks.\n\n**Unified resource visibility.** View Terraform-managed resources alongside Pulumi-managed resources in [Resource Search](https://www.pulumi.com/docs/insights/discovery/search/). Each Terraform resource appears in the console using a `pulumi:terraform:` naming convention, so you can search and filter using the attribute names you already know.\n\n**Audit policies.** Run [audit (detective) policy packs](https://www.pulumi.com/docs/insights/policy/policy-groups/) against your Terraform-managed stacks, including Pulumi&rsquo;s [pre-built compliance packs](https://www.pulumi.com/docs/insights/policy/policy-packs/pre-built-packs/) 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.\n\n**Stack outputs and references.** Terraform root module outputs are automatically mapped to Pulumi [stack outputs](https://www.pulumi.com/docs/iac/concepts/stacks/#outputs), making them available via [stack references](https://www.pulumi.com/docs/iac/concepts/stacks/#stackreferences) and the [`pulumi-stacks` ESC provider](https://www.pulumi.com/docs/esc/integrations/infrastructure/pulumi-iac/pulumi-stacks/). 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.\n\n## How it works\n\nPulumi Cloud implements the [Terraform remote backend API](https://developer.hashicorp.com/terraform/language/backend/remote). You point the Terraform CLI at Pulumi Cloud using the standard `backend \"remote\"` configuration block, and no changes to your Terraform code or workflow are required.\n\nEach Terraform workspace maps to a Pulumi stack. The workspace name follows the convention `_`. For example, `networking_prod` creates a stack named `prod` in the `networking` project.\n\n## Get started\n\nMigration from S3, Azure Blob, GCS, local backends, or HCP Terraform (Terraform Cloud) takes minutes and is documented in the [Terraform state backend guide](https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/). From S3, Azure Blob, GCS, or local state, back up your state, update your backend block to point to Pulumi Cloud, set `TF_TOKEN_api_pulumi_com`, and run `terraform init -migrate-state`. From HCP Terraform, export state manually and push it to Pulumi Cloud.\n\nEach Terraform resource stored in Pulumi Cloud counts as a resource under management, the same as a Pulumi-managed resource. See the [pricing page](https://www.pulumi.com/pricing/) for details.\n\n[\nStore Terraform State in Pulumi Cloud\n](https://www.pulumi.com/docs/iac/get-started/terraform/terraform-state-backend/)\n\nIf you have questions or feedback, join us in the [Pulumi Community Slack](https://slack.pulumi.com/) or open an issue on [GitHub](https://github.com/pulumi/pulumi).","publishedAt":"2026-03-05T00:00:00.000Z","url":"https://www.pulumi.com/blog/terraform-state-backend-pulumi-cloud/","media":[]},{"id":"rel_qL0Dg1Or1vdho2SDRmZ2M","version":null,"title":"Token Efficiency vs Cognitive Efficiency: Choosing IaC for AI Agents","summary":"![](https://www.pulumi.com/blog/token-efficiency-vs-cognitive-efficiency-choosing-iac-for-ai-agents/meta.png)\n\nWhen an AI agent writes infrastructure ...","content":"![](https://www.pulumi.com/blog/token-efficiency-vs-cognitive-efficiency-choosing-iac-for-ai-agents/meta.png)\n\nWhen an AI agent writes infrastructure code, two things matter: how compact the output is (token efficiency) and how well the model actually reasons about what it&rsquo;s writing (cognitive efficiency). HCL produces fewer tokens for the same resource. But does that make it the better choice when agents need to refactor, debug, and iterate? We ran a benchmark across [Claude Opus 4.6](https://docs.anthropic.com/en/docs/about-claude/models) and [GPT-5.2-Codex](https://platform.openai.com/docs/models) to find out.\n\n## These two goals pull in opposite directions\n\nYou might assume that the language producing fewer tokens is also the one models reason about best. Research into LLM-driven infrastructure generation suggests otherwise.\n\n## Where HCL wins on tokens\n\nHCL is declarative and minimal. It requires no imports, no runtime constructs, and no language scaffolding. For simple infrastructure generation, HCL leads to fewer tokens and lower generation cost.\n\nFor a straightforward resource definition, HCL gets straight to the point:\n\n```\nresource \"aws_s3_bucket\" \"example\" {\n bucket = \"my-bucket\"\n}\n\n```\n\nCompare that with the Pulumi TypeScript equivalent:\n\n```\nimport * as aws from \"@pulumi/aws\";\n\nconst bucket = new aws.s3.Bucket(\"example\", {\n bucket: \"my-bucket\",\n});\n\n```\n\nThe HCL version requires fewer tokens. No import statement, no variable declaration, no constructor syntax. For single-shot generation of simple resources, that compactness matters. But the picture changes once you account for deployability and refactoring.\n\n## What the data shows\n\nHCL&rsquo;s token advantage is real for simple generation. But agents don&rsquo;t just generate once. They validate, repair failures, and refactor. We built a benchmark that measures the full cycle: an open-source tool that sends identical prompts to Claude Opus 4.6 (`claude-opus-4-6`) and OpenAI GPT-5.2-Codex (`gpt-5.2-codex`), requesting both Terraform HCL and Pulumi TypeScript for the same AWS infrastructure (VPC with public and private subnets across 2 AZs, an EC2 instance with security groups for SSH and HTTP, and an RDS PostgreSQL instance with a security group allowing port 5432 only from the EC2 security group, plus all networking: internet gateway, NAT gateway, route tables, and associations). We measured token consumption, cost, and deployability across two scenarios: initial generation and refactoring into reusable components.\n\n**Methodology:** Temperature 0, 5 runs per combination, randomized execution order. Each generated output goes through a three-stage validation pipeline: formatting (`terraform fmt` for HCL, `prettier` for TypeScript), static analysis (`terraform validate` for HCL, `tsc --noEmit` for TypeScript), and provider-level validation (`terraform plan` for HCL, `pulumi preview` for TypeScript). Both plan and preview check against real AWS provider schemas without creating resources, making their pass rates comparable across formats. If plan/preview fails, the benchmark feeds the error back to the model for one self-repair attempt. At temperature 0, Claude Opus 4.6 produced near-identical outputs across runs (sd=0-4 tokens). GPT-5.2-Codex showed more natural variation (sd=130-165 tokens). With 5 runs per combination the results are directional, not statistically conclusive. Costs are estimates based on published pricing as of 2026-02-22. Full methodology and reproducible code:\n\n[\n![GitHub repository: dirien/iac-token-benchmark](https://opengraph.githubassets.com/1/dirien/iac-token-benchmark)\n\n**\ngithub.com/dirien/iac-token-benchmark\n\n](https://github.com/dirien/iac-token-benchmark)\n\n### Scenario 1: Generation\n\nHCL uses fewer tokens for generation:\n\nProvider\nFormat\nOutput tokens (mean)\nLOC (mean)\nCost (mean)\nPlan/Preview pass\nRepairs needed\n\nClaude Opus 4.6\nTerraform\n2,007\n212\n$0.051\n5/5\n0/5\n\nClaude Opus 4.6\nPulumi TS\n2,555\n200\n$0.065\n5/5\n0/5\n\nGPT-5.2-Codex\nTerraform\n1,565\n110\n$0.022\n2/5\n2/5\n\nGPT-5.2-Codex\nPulumi TS\n2,322\n147\n$0.033\n0/5\n5/5\n\nHCL produces 21-33% fewer output tokens across both models. For simple resource generation, this translates directly to lower cost. Pulumi TypeScript uses more tokens for fewer lines of code because imports, type annotations, and constructor syntax add tokens without adding functional lines.\n\nThe Plan/Preview column tells a more complete story. Claude Opus 4.6 produced deployable code on the first pass for both formats: 5/5 for Terraform and 5/5 for Pulumi. Neither needed repairs. GPT-5.2-Codex struggled with both formats, but Terraform fared slightly better (2/5 vs 0/5).\n\n### Scenario 2: Refactoring into reusable components\n\nWe took each model&rsquo;s generation output and asked it to refactor the code into a reusable module or component with parameterized environment name, instance sizes, and availability zone count.\n\nProvider\nFormat\nOutput tokens (mean)\nLOC (mean)\nCost (mean)\nPlan/Preview pass\n\nClaude Opus 4.6\nPulumi TS\n2,720\n218\n$0.082\n5/5\n\nClaude Opus 4.6\nTerraform\n3,379\n345\n$0.095\n5/5\n\nGPT-5.2-Codex\nPulumi TS\n2,477\n248\n$0.038\n4/5\n\nGPT-5.2-Codex\nTerraform\n1,356\n119\n$0.021\n0/5\n\nThis is where the results get interesting. Opus + Pulumi refactoring used 20% fewer tokens, cost 14% less, and passed `pulumi preview` on every run (5/5) with zero repairs. Opus + Terraform also ended up at 5/5 for `terraform plan`, but it needed repair cycles to get there. The benchmark run log tells the story:\n\n```\n# Pulumi refactoring: runs 29-33, sequential, no gaps = zero repairs\n✓ [29/40] anthropic/pulumi-ts/refactor run 1 — 2721 tokens, $0.0817\n✓ [30/40] anthropic/pulumi-ts/refactor run 2 — 2721 tokens, $0.0817\n✓ [31/40] anthropic/pulumi-ts/refactor run 3 — 2721 tokens, $0.0817\n✓ [32/40] anthropic/pulumi-ts/refactor run 4 — 2721 tokens, $0.0817\n✓ [33/40] anthropic/pulumi-ts/refactor run 5 — 2714 tokens, $0.0816\n\n# Terraform refactoring: 34→36→38→40→42, every run skips a number = every run triggered self-repair\n✓ [34/40] anthropic/terraform/refactor run 1 — 3388 tokens, $0.0956\n✓ [36/40] anthropic/terraform/refactor run 2 — 3339 tokens, $0.0944\n✓ [38/40] anthropic/terraform/refactor run 3 — 3390 tokens, $0.0957\n✓ [40/40] anthropic/terraform/refactor run 4 — 3388 tokens, $0.0956\n✓ [42/40] anthropic/terraform/refactor run 5 — 3388 tokens, $0.0956\n\n```\n\nThe skipped numbers (35, 37, 39, 41) are self-repair turns where the model received `terraform plan` errors and regenerated the code. Each repair consumed additional tokens that do not show up in the first-generation cost but do show up in the total pipeline cost.\n\nGPT-5.2-Codex tells a different story. Both formats needed repair on every run, but what happened after repair is what matters:\n\n```\n# Codex + Terraform refactoring: repaired, but still failed plan (0/5 deployable)\nterraform run 1 turn 2: plan_valid=False tokens=1559\nterraform run 2 turn 2: plan_valid=False tokens=1165\nterraform run 3 turn 2: plan_valid=False tokens=1068\nterraform run 4 turn 2: plan_valid=False tokens=1134\nterraform run 5 turn 2: plan_valid=False tokens=1101\n\n# Codex + Pulumi refactoring: repaired, and preview passed (4/5 deployable)\npulumi-ts run 1 turn 2: plan_valid=True tokens=2246\npulumi-ts run 2 turn 2: plan_valid=True tokens=2567\npulumi-ts run 3 turn 2: plan_valid=True tokens=2187\npulumi-ts run 4 turn 2: plan_valid=True tokens=2531\npulumi-ts run 5 turn 2: plan_valid=False tokens=2647\n\n```\n\nCodex + Terraform used fewer tokens but produced zero deployable refactored code after repair. Codex + Pulumi used more tokens but recovered to deployable code 4 out of 5 times. TypeScript&rsquo;s type errors gave the model enough information to fix the problems. HCL&rsquo;s plan errors did not.\n\n### Total pipeline cost\n\nThis is the number that matters for production agent workflows. It includes generation, any self-repair cycles, and refactoring:\n\nProvider\nFormat\nTotal tokens (mean)\nTotal cost (mean)\n\nClaude Opus 4.6\nPulumi TS\n8,183\n$0.146\n\nClaude Opus 4.6\nTerraform\n14,669\n$0.249\n\nGPT-5.2-Codex\nTerraform\n8,723\n$0.084\n\nGPT-5.2-Codex\nPulumi TS\n15,211\n$0.138\n\nOpus + Pulumi had the lowest total pipeline cost at $0.146, 41% cheaper than Opus + Terraform at $0.249. The difference comes entirely from repair cycles: Pulumi needed zero repairs across both scenarios, while Terraform refactoring triggered self-repair on every run.\n\nWith Codex, Terraform had the lower pipeline cost ($0.084 vs $0.138), driven by its smaller token output. But Codex + Terraform produced zero deployable refactored code (0/5 plan pass), while Codex + Pulumi produced deployable code 4 out of 5 times.\n\n### What this means\n\n- **HCL uses fewer tokens per generation.** For single-shot resource creation, HCL&rsquo;s compactness saves 21-33% on output tokens. That advantage is consistent across both models.\n\n- **Pulumi produces deployable refactored code more reliably.** With Opus, Pulumi refactoring passed preview 5/5 with zero repairs. Codex + Pulumi passed 4/5. Codex + Terraform passed 0/5.\n\n- **Total pipeline cost favors Pulumi with Opus.** Opus + Pulumi cost 41% less than Opus + Terraform across the full pipeline ($0.146 vs $0.249), because Terraform refactoring needed repair cycles that Pulumi did not.\n\n- **The tradeoff depends on your model and workflow.** Codex + Terraform is cheapest on raw tokens but produces no deployable refactored code. Codex + Pulumi costs more per token but actually deploys. Opus + Pulumi is the best of both: fewer refactoring tokens and zero repairs.\n\n## Why Pulumi refactoring deploys cleaner\n\nThe [TerraFormer project](https://arxiv.org/abs/2601.08734) identified what they call the **correctness-congruence gap**: LLMs generate configurations that look valid but fail to match the user&rsquo;s architectural intent. An [error taxonomy study](https://arxiv.org/abs/2512.14792) cataloged the same pattern across models. A [survey of LLMs for IaC](https://arxiv.org/html/2404.00227v1) found the gap between syntax validity and architectural correctness widens with infrastructure complexity.\n\nRefactoring is where this gap bites hardest. Turning a flat resource list into a parameterized, reusable module requires the model to restructure dependencies, introduce variables, and compose abstractions. With Pulumi, the model can use TypeScript&rsquo;s standard refactoring patterns: extract a class, add typed constructor parameters, compose functions. These are patterns it has practiced across millions of repositories during training. With HCL, the same refactoring requires `count`, `for_each`, `dynamic` blocks, and module variable plumbing, domain-specific constructs that have far less representation in training data.\n\nOur benchmark confirms this directly. Opus produced 2,720 tokens for Pulumi refactoring versus 3,379 for Terraform, a 20% reduction, and every Pulumi run passed `pulumi preview` without repair. The Terraform refactoring runs all triggered self-repair because the restructured HCL modules had issues that `terraform plan` caught.\n\nTraining data distribution makes this structural. LLMs have far more TypeScript than HCL in their corpora. A model refactoring TypeScript draws on patterns from the entire open-source ecosystem. A model refactoring HCL modules has a much smaller pool. Since general-purpose languages dominate new code production, this gap will widen over time.\n\n**\n\nTooling can close the gap further. The [Pulumi MCP server](https://www.pulumi.com/docs/iac/using-pulumi/mcp-server/) gives AI agents direct access to resource schemas at generation time. A tool like `get-resource` returns every property, type, and required field for a given cloud resource. The agent does not have to guess from what it memorized during training. It can look up the correct schema before writing a single line of code.\n\nThis changes the workflow from &ldquo;generate, fail, read error, retry&rdquo; to &ldquo;look up schema, generate correctly.&rdquo; Agent skills push this further by encoding working Pulumi idioms as structured prompts, so the model starts from a known-good baseline. Terraform has no equivalent to this MCP-based schema lookup. That difference matters more with every iteration.\n\n## Where the industry is heading\n\nOne way to think about IaC language choice is through the lens of [AI engineering maturity levels](https://www.principalengineer.com/p/the-7-levels-of-software-engineering). At Level 3 (agentic coding), agents generate infrastructure from prompts. HCL&rsquo;s 21-33% token savings on generation matters here. At Levels 4-5, agents iterate on specifications, refactor code, and maintain systems over time. Our benchmark shows this is where Pulumi pulls ahead: 41% lower total pipeline cost with Opus, and more deployable refactored output with both models.\n\nThe industry is moving toward Levels 4-5. Agents are taking on refactoring, feature flags, environment parameterization. [43% of DevOps teams need four or more deployment iterations](https://overmind.tech/blog/the-best-ai-for-terraform) before infrastructure is production-ready. The first-generation token advantage HCL holds applies to the task that is shrinking as a share of agent workloads. The refactoring and deployability advantages that Pulumi offers apply to the tasks that are growing.\n\n## Choosing based on your workflow\n\nIf your agents primarily generate well-scoped resource definitions, HCL saves 21-33% on output tokens. That advantage is real and consistent.\n\nIf your agents need deployable output on the first pass (which avoids repair costs entirely), our data shows Opus + Pulumi is the strongest combination: 5/5 plan/preview pass for both generation and refactoring, zero repairs, lowest total pipeline cost.\n\nIf your agents evolve infrastructure over time through refactoring and modularizing, Pulumi produced deployable refactored code more reliably across both models we tested (5/5 and 4/5 vs 5/5 and 0/5 for Terraform).\n\nPulumi covers the full iteration loop, from generation through repair to refactoring, using the same language patterns and tooling that models already know.\n\n## Get started\n\nReady to explore how AI agents work with Pulumi? Check out [Pulumi AI](https://www.pulumi.com/ai/) to see LLM-powered infrastructure generation in action, or get started with [Pulumi&rsquo;s documentation](https://www.pulumi.com/docs/get-started/).\n\nJoin the conversation in the [Pulumi Community Slack](https://slack.pulumi.com/) or [Pulumi Community Discussions](https://github.com/pulumi/pulumi/discussions).","publishedAt":"2026-03-03T00:00:00.000Z","url":"https://www.pulumi.com/blog/token-efficiency-vs-cognitive-efficiency-choosing-iac-for-ai-agents/","media":[]}],"pagination":{"page":1,"pageSize":20,"totalPages":3,"totalItems":53},"summaries":{"rolling":{"windowDays":90,"summary":"Pulumi shipped broad platform expansion across AI infrastructure management, governance tooling, and developer experience. Bun graduated from package manager to first-class runtime for Pulumi programs, eliminating the Node.js dependency for TypeScript execution. Pulumi Neo gained critical collaboration features—Plan Mode for deliberate upfront discovery before execution, read-only task permissions to sandbox AI operations, and task sharing for organizational visibility—while Neo's migration capabilities expanded to orchestrate zero-downtime transitions from CDK, Terraform, and ARM templates. On the governance side, Pulumi shipped `pulumi policy analyze` to validate stack state against policies without running programs, locked down ESC values with `fn::final` to prevent child environment overrides, and introduced schema validation and Terraform state backend support to unify infrastructure management across tools. A 20x performance improvement from journaling moved to general availability, and the platform extended identity options with Google Sign-In, multi-VCS support (GitHub Enterprise, Azure DevOps, GitLab), and Pulumi IAM availability for self-hosted deployments.","releaseCount":44,"generatedAt":"2026-04-11T14:00:45.384Z"},"monthly":[{"year":2026,"month":3,"summary":"Pulumi focused on safety and control throughout March, launching read-only and plan-first modes for Neo alongside expanded IAM capabilities for tag-based access and team role assignments. The month also brought governance advances—OPA/Rego reached stable parity with native policy SDKs, ESC gained fn::final to lock down inherited values, and Insights expanded to customer-managed runners for regulated environments. Infrastructure tooling broadened with Terraform state backend support in Pulumi Cloud, Google Sign-In for authentication, and multi-provider version control integration, while journaling—a 20x performance improvement shipped in January—graduated to general availability by default.","releaseCount":14,"generatedAt":"2026-04-11T14:00:48.148Z"}]}}