Better CLI Interactions for Agents and Humans

AI agents do a lot of their work through CLIs. They’re easier to call than HTTP APIs and they produce predictable output. Over the last few months our own CLI traffic has shifted from mostly people typing commands to people and agents running commands together, often in the same session.
Today we’re shipping a release built for both. The Pulumi CLI is reorganized around three ideas: the right command should be the one you can guess, anything you can do in Pulumi Cloud should also be doable from the terminal, and what comes back should be just as readable to an agent as it is to a person.
Designing for guessability
The bar we set was that both developers and coding agents should be able to guess at the right command for a particular task: pulumi env edit to modify an environment, pulumi stack get to see what’s going on with a stack, pulumi org member list to see who’s on the team. If we had to explain which command did what, the usability bar hadn’t been met.
Branches in the tree are now singular nouns like stack, env, org, and deployment. Leaves are now verbs from a canonical vocabulary — list, get, set, new, edit, remove — and they mean the same thing wherever they’re used. edit always means modify an existing thing. Wherever the old vocabulary differed, though, the old name still works: ls, rm, update, and open are all aliased to preserve backward compatibility.
For the most part, product names have also been replaced with familiar nouns. Users (human or otherwise) don’t think in product names; they think in terms of resources, stacks, environments. For example, take Pulumi ESC: the product may be named ESC (and for a while the command was too), but nobody thinks I need to initialize a new ESC — they think I need to create a new environment. The command is therefore pulumi env new, with esc init preserved as an alias to avoid disrupting anyone’s existing workflows.
<span class="line"><span class="cl">$ pulumi env new my-project my-env
</span></span><span class="line"><span class="cl">Environment created.
</span></span>
All of Pulumi Cloud in the terminal
Up to now, most of what you could do with Pulumi Cloud had to be done either in the browser or through direct API calls. Things like reviewing deployments, setting up webhooks, finding non-compliant resources, or managing deployment settings all required you to break out curl and hit the API docs or open a browser and navigate the Pulumi Cloud console.
That changes today. Pulumi Cloud is now fully accessible from the command line through the pulumi CLI, with consistently named nouns and verbs aligned to what you’d expect:
-
pulumi stack getreturns a complete stack overview, metadata, resource list, and more:<span class="line"><span class="cl">$ pulumi stack get <span class="se">\ </span></span></span><span class="line"><span class="cl"> --stack cnunciato/chris.nunciato.org/production <span class="se">\ </span></span></span><span class="line"><span class="cl"> --output json <span class="p">|</span> jq -r <span class="s2">".resources[].type"</span> <span class="p">|</span> grep <span class="s2">"aws:s3"</span> </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">aws:s3:BucketEventSubscription </span></span><span class="line"><span class="cl">aws:s3/bucket:Bucket </span></span><span class="line"><span class="cl">aws:s3/bucket:Bucket </span></span><span class="line"><span class="cl">aws:s3/bucketPublicAccessBlock:BucketPublicAccessBlock </span></span><span class="line"><span class="cl">aws:s3/bucketWebsiteConfiguration:BucketWebsiteConfiguration </span></span><span class="line"><span class="cl">aws:s3/bucketOwnershipControls:BucketOwnershipControls </span></span><span class="line"><span class="cl">aws:s3/bucketNotification:BucketNotification </span></span>… with other stack-related commands like
pulumi stack history get events,pulumi stack drift list,pulumi stack schedule new, andpulumi stack webhook newalongside it. -
Organizational commands like
pulumi org member list,pulumi org role list,pulumi org usage get, andpulumi org audit-log exportcan help you dig into the details when you need to as well. -
Deployment-related commands like
pulumi deployment list,get,log, andcancellet you see what’s running, dive into what happened, and take action without having to leave the terminal.<span class="line"><span class="cl">$ pulumi deployment list <span class="se">\ </span></span></span><span class="line"><span class="cl"> --stack cnunciato/chris.nunciato.org/production <span class="se">\ </span></span></span><span class="line"><span class="cl"> --output table </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">┌──────────────────────────────────────┬───────────┬─────────┬───────────┬──────────────┬─────────────────────────┐ </span></span><span class="line"><span class="cl">│ ID │ OPERATION │ VERSION │ STATUS │ INITIATED BY │ MODIFIED │ </span></span><span class="line"><span class="cl">├──────────────────────────────────────┼───────────┼─────────┼───────────┼──────────────┼─────────────────────────┤ </span></span><span class="line"><span class="cl">│ 83e44b8c-643c-4e9f-9f36-0c6a81d9db2e │ update │ <span class="m">140</span> │ running │ cnunciato │ 2026-05-17 21:26:37.340 │ </span></span><span class="line"><span class="cl">│ 52a37cbe-b7fd-4027-8e0f-7b4785ab12e8 │ update │ <span class="m">139</span> │ succeeded │ cnunciato │ 2026-05-16 23:36:07.999 │ </span></span><span class="line"><span class="cl">│ 94e04525-b3a4-42b5-9987-e344018a3324 │ preview │ <span class="m">138</span> │ succeeded │ cnunciato │ 2026-05-16 23:29:19.709 │ </span></span><span class="line"><span class="cl">└──────────────────────────────────────┴───────────┴─────────┴───────────┴──────────────┴─────────────────────────┘ </span></span> -
And when you need to query across managed (and even unmanaged) resources,
pulumi insights resource searchandgetcan help you find what you’re looking for quickly:<span class="line"><span class="cl">$ pulumi insights resource search <span class="se">\ </span></span></span><span class="line"><span class="cl"> --query <span class="s1">'type:aws:s3/bucket:Bucket org:cnunciato project:photomap stack:dev'</span> <span class="se">\ </span></span></span><span class="line"><span class="cl"> --output table </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">┌──────────────────────────────────────────────────────────────────────────┬──────────────────────┬───────┬──────────────────────────┐ </span></span><span class="line"><span class="cl">│ URN │ TYPE │ STACK │ MODIFIED │ </span></span><span class="line"><span class="cl">├──────────────────────────────────────────────────────────────────────────┼──────────────────────┼───────┼──────────────────────────┤ </span></span><span class="line"><span class="cl">│ urn:pulumi:dev::photomap::aws:apigateway:x:API<span class="nv">$aws</span>:s3/bucket:Bucket::api │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │ </span></span><span class="line"><span class="cl">│ urn:pulumi:dev::photomap::aws:s3/bucket:Bucket::images │ aws:s3/bucket:Bucket │ dev │ 2020-10-31T00:39:47.926Z │ </span></span><span class="line"><span class="cl">└──────────────────────────────────────────────────────────────────────────┴──────────────────────┴───────┴──────────────────────────┘ </span></span><span class="line"><span class="cl"> </span></span><span class="line"><span class="cl">Showing <span class="m">2</span> of <span class="m">2</span> resources. </span></span>
Flags and output formats are consistent across commands (--output table, json), as are the shapes of cross-cutting features like webhooks. If you’ve used pulumi stack webhook, for example, you already know how to use pulumi env webhook and pulumi org webhook, and so on.
Direct access to the Pulumi Cloud API
For any features of Pulumi Cloud that don’t yet have their own commands, you’ve also got pulumi api. It’s a gh api-inspired command designed to give you direct access to the full REST API, without having to manage separate access tokens, auth settings, or request/response payloads. Everything is handled for you through your authenticated pulumi CLI.
There’s even pulumi api list, which enumerates every single endpoint that’s exposed:
<span class="line"><span class="cl">$ pulumi api list
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">┌───────────────┬────────┬───────────────────────────────────────┬──────────────────────────────┐
</span></span><span class="line"><span class="cl">│ TAG │ METHOD │ PATH │ SUMMARY │
</span></span><span class="line"><span class="cl">├───────────────┼────────┼───────────────────────────────────────┼──────────────────────────────┤
</span></span><span class="line"><span class="cl">│ AccessTokens │ GET │ /api/orgs/<span class="o">{</span>orgName<span class="o">}</span>/tokens │ ListOrgTokens │
</span></span><span class="line"><span class="cl">│ AccessTokens │ POST │ /api/orgs/<span class="o">{</span>orgName<span class="o">}</span>/tokens │ CreateOrgToken │
</span></span><span class="line"><span class="cl">│ AccessTokens │ DELETE │ /api/orgs/<span class="o">{</span>orgName<span class="o">}</span>/tokens/<span class="o">{</span>tokenId<span class="o">}</span> │ DeleteOrgToken │
</span></span><span class="line"><span class="cl">│ AccessTokens │ GET │ /api/user/tokens │ ListPersonalTokens │
</span></span><span class="line"><span class="cl">│ AccessTokens │ POST │ /api/user/tokens │ CreatePersonalToken │
</span></span><span class="line"><span class="cl">│ AccessTokens │ DELETE │ /api/user/tokens/<span class="o">{</span>tokenId<span class="o">}</span> │ DeletePersonalToken │
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="m">537</span> operations. Pass --output<span class="o">=</span>json <span class="k">for</span> a stable, scriptable contract.
</span></span>
To get the details about a particular API, use pulumi api describe:
<span class="line"><span class="cl">$ pulumi api describe <span class="s1">'DELETE /api/user/tokens/{tokenId}'</span> <span class="c1"># or DeletePersonalToken</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">DELETE /api/user/tokens/<span class="o">{</span>tokenId<span class="o">}</span>
</span></span><span class="line"><span class="cl">Tag: AccessTokens
</span></span><span class="line"><span class="cl">Operation: DeletePersonalToken
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">DeletePersonalToken
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Permanently deletes a personal access token by its identifier. The token is immediately
</span></span><span class="line"><span class="cl">invalidated and can no longer be used <span class="k">for</span> authentication. Returns <span class="m">204</span> on success or <span class="m">404</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> the token does not exist.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Parameters:
</span></span><span class="line"><span class="cl"> <span class="o">[</span>path<span class="o">]</span> tokenId* <span class="o">(</span>string<span class="o">)</span> — The access token identifier
</span></span>
All requests are made through your authenticated pulumi CLI:
<span class="line"><span class="cl">$ pulumi login
</span></span><span class="line"><span class="cl">Logged in to pulumi.com as cnunciato.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ pulumi whoami
</span></span><span class="line"><span class="cl">cnunciato
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ pulumi api /api/user/tokens/2cf15c7d-afad-458f-ace0-fc7ff0512b10 <span class="se">\
</span></span></span><span class="line"><span class="cl"> --method DELETE <span class="o">&&</span> <span class="nb">echo</span> <span class="s2">"Token deleted."</span>
</span></span><span class="line"><span class="cl">Token deleted.
</span></span>
Newly published endpoints are available through pulumi api immediately, so you don’t have to wait for a new CLI release before you can start using them. See the Pulumi Cloud REST API documentation to learn more.
Finding templates in the Pulumi Cloud Registry
Finding out which templates are available to you through your Pulumi organization used to mean having to navigate to the Pulumi Cloud Registry and start searching. The new pulumi template commands make this easier by letting you ask for what’s available right from the shell, either by fetching the full list or filtering with the --name or --search params:
<span class="line"><span class="cl">$ pulumi template list --search <span class="s2">"container typescript"</span> --org cnunciato
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">┌─────────────────────────────────────────────┬────────┬────────────┬────────────┐
</span></span><span class="line"><span class="cl">│ Name │ Source │ Language │ Visibility │
</span></span><span class="line"><span class="cl">├─────────────────────────────────────────────┼────────┼────────────┼────────────┤
</span></span><span class="line"><span class="cl">│ pulumi/templates/container-aws-typescript │ github │ typescript │ public │
</span></span><span class="line"><span class="cl">│ pulumi/templates/container-azure-typescript │ github │ typescript │ public │
</span></span><span class="line"><span class="cl">│ pulumi/templates/container-gcp-typescript │ github │ typescript │ public │
</span></span><span class="line"><span class="cl">└─────────────────────────────────────────────┴────────┴────────────┴────────────┘
</span></span>
This is especially useful when you’re working with an agent because it helps the agent discover your org’s approved templates without having to name them. Start with a prompt that tells the agent what you want to build, and let the agent find the right template for you.
Agent-friendly Markdown docs for providers and components
Both humans and agents need to be able to understand what’s inside a Pulumi package before they can use it. And while the Registry is an excellent resource for that, it was mainly designed to deliver HTML — a human-friendly format that agents can certainly use, but that’s much more verbose than they actually need.
With pulumi api, agents can fetch the details about a package from the Registry directly and get back those details either in markdown or json, whichever works best, filtering on properties like language where applicable:
<span class="line"><span class="cl">$ pulumi api <span class="s2">"/api/registry/packages/pulumi/pulumi/random/versions/4.19.1"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"name"</span>: <span class="s2">"random"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"publisher"</span>: <span class="s2">"pulumi"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"publisherDisplayName"</span>: <span class="s2">"Pulumi"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"source"</span>: <span class="s2">"pulumi"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"version"</span>: <span class="s2">"4.19.1"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"description"</span>: <span class="s2">"A Pulumi package to safely use randomness in Pulumi programs."</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"repoUrl"</span>: <span class="s2">"https://github.com/pulumi/pulumi-random"</span>,
</span></span><span class="line"><span class="cl"> ...
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span>
<span class="line"><span class="cl">$ pulumi api <span class="s2">"/api/registry/packages/pulumi/pulumi/random/versions/4.19.1/docs/random%3Aindex%2FrandomPassword%3ARandomPassword"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"> --output markdown
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># RandomPassword</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">resource <span class="sb">`</span>random:index/randomPassword:RandomPassword<span class="sb">`</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">## Example Usage</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">package main
</span></span><span class="line"><span class="cl">...
</span></span>
Resources are individually addressable using their URL-encoded Pulumi type tokens — e.g., random:index/randomPassword:RandomPassword — and API endpoints are configured to deliver Markdown when agents ask for it:
<span class="line"><span class="cl">$ curl <span class="s2">"https://api.pulumi.com/api/registry/packages/pulumi/pulumi/random/versions/latest/readme?lang=python"</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"> -H <span class="s2">"Accept: text/markdown"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Installation</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">The Random provider is available as a package in all Pulumi languages:
</span></span><span class="line"><span class="cl">...
</span></span>
Even compared to JSON (which is itself a significant improvement over HTML), Markdown is a much more token-efficient format for agents to work with:
Package
Endpoint
JSON
Markdown
Tokens saved
random
/readme
10.68 KB
6.04 KB
43%
aws
/readme
4.22 KB
2.54 KB
40%
aws
/nav?depth=full
204 KB
170 KB
17%
aws
/docs/{resource token}
15.24 KB
11.28 KB
26%
azure-native
/docs/{resource token}
48.13 KB
30.37 KB
37%
aws
/docs/{function token}
2.40 KB
1.46 KB
39%
Learn more about our Registry endpoints in the REST API docs. (Or just ask your agent!)
New to the CLI: Pulumi Neo
When we launched Pulumi Neo last year, the only way to use it was in the Pulumi Cloud Console. But while there’s a ton you can do with Neo in the browser, if you’re an engineer already living in the terminal, chances are that eventually you’re going to wish you had Neo right in the CLI along with you.
Now you do. Running pulumi neo with or without a prompt launches a Pulumi Cloud-connected session that gives Neo access to your local environment just like any other coding agent. Use it on its own to scaffold a new project, understand an existing codebase, or debug a failing deployment — or pull it into an active session with the coding agent you’re already using. Either way, it stays in the shell you’re already working in.
We’ll cover Neo in the CLI in more detail later this week. In the meantime, here’s a peek:
Smaller changes that add up
A long list of smaller changes also runs through this release:
-
The core loop now speaks JSON end to end, with
pulumi up,pulumi destroy, andpulumi importall emitting structured JSON output when called with--output json. -
Streams now behave the way scripts expect them to, with data on stdout, progress and diagnostics on stderr.
-
Exit codes are more consistent across the board. Every failure mode — auth, resource, policy, missing stack, cancellation, timeout, and others — has its own exit code, so agents can branch on the actual cause instead of having to interpret output. The full table is in the docs.
-
Help text explains why a command exists, not just what it does, and includes at least one concrete example. Examples in
--helpare one of the most effective ways to improve LLM accuracy on first-try invocations — and it turns out they’re pretty handy for humans, too.
A sneak peek at a new command
Later this week, you’ll get a closer look at pulumi do, a new top-level command that enables direct resource operations like create, read, update, delete, and list across every Pulumi-supported cloud provider and resource, all in one command. A simple example:
<span class="line"><span class="cl">$ pulumi <span class="k">do</span> aws getAvailabilityZones
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"groupNames"</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"us-west-2-zg-1"</span>
</span></span><span class="line"><span class="cl"> <span class="o">]</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"id"</span>: <span class="s2">"us-west-2"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"names"</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"us-west-2a"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"us-west-2b"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"us-west-2c"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"us-west-2d"</span>
</span></span><span class="line"><span class="cl"> <span class="o">]</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"region"</span>: <span class="s2">"us-west-2"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"zoneIds"</span>: <span class="o">[</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"usw2-az2"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"usw2-az1"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"usw2-az3"</span>,
</span></span><span class="line"><span class="cl"> <span class="s2">"usw2-az4"</span>
</span></span><span class="line"><span class="cl"> <span class="o">]</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span>
It might look like that’s calling the AWS CLI, but it’s not — it’s using the same AWS provider function a full Pulumi program would use, only without the program, and invoked directly from the CLI.
More on how it works, and what you can do with it, in the days ahead.
Try it yourself
A lot of what makes a developer tool worth using is in the details, and most of what’s in this release is exactly that, across the whole CLI, with humans and agents in mind.
We’d love for you to grab the latest release and give it a try. Tell us what’s now easy, what’s still hard, and what to fix next on GitHub or in the community Slack. The fastest way the CLI gets better is feedback from the humans and agents who live in it.
Fetched May 19, 2026


