pulumi-automation-api — Claude Code skill: run Pulumi from code
Tells the agent how to drive Pulumi from a program instead of the CLI: LocalWorkspace, createOrSelectStack, inline programs.
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a claude-codeWhat pulumi-automation-api does
The skill loads when you ask how to run Pulumi operations programmatically. It covers the Automation API: rather than calling pulumi up in a shell, you call functions in your code that do the same work. The pieces it walks through are LocalWorkspace, createOrSelectStack and inline programs.
A good chunk is about picking an architecture. Local Source points at an existing project through workDir; Inline Source keeps the program inside the orchestrator. There are examples for deploying several stacks in dependency order, running independent stacks in parallel, setting config with setConfig, and reading outputs after up. The orchestrator can be written in a different language than the programs it manages.
The skill deploys nothing on its own. It hands the agent TypeScript patterns, so running those examples assumes Pulumi is installed and cloud credentials are configured. One project with a plain deployment and no need for programmatic control gets little out of it.
What it helps with
- sequence a deployment across several stacks
- replace brittle shell scripts wrapping pulumi commands
- build an internal portal where developers request infrastructure
- pass outputs from one stack into another in code
- deploy independent stacks in parallel
Example prompts for the agent
- Show me how to deploy three stacks in order with the Automation API
- How do I set aws:region on a stack programmatically before up?
- Write an inline Pulumi program inside a Go orchestrator
How to install pulumi-automation-api
1Skills CLI (Vercel)
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a claude-code2Manually: put the files in place
~/.claude/skills/pulumi-automation-api/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/pulumi-automation-api/
1Skills CLI (Vercel)
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a codex2Manually: put the files in place
.agents/skills/pulumi-automation-api/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a cursor2Manually: put the files in place
.cursor/skills/pulumi-automation-api/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install pulumi/agent-skills pulumi-automation-api2Manually: put the files in place
.github/skills/pulumi-automation-api/SKILL.md1Skills CLI (Vercel)
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a gemini-cli2Platform CLI
gemini skills install https://github.com/pulumi/agent-skills --path pulumi/skills/pulumi-automation-apiManually: put the files in place
.devin/skills/pulumi-automation-api/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add pulumi/agent-skills --skill pulumi-automation-api -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about pulumi-automation-api
How do I install pulumi-automation-api in Claude?
Run npx skills add pulumi/agent-skills --skill pulumi-automation-api -a claude-code. The skill file then sits at ~/.claude/skills/pulumi-automation-api/SKILL.md.
What does pulumi-automation-api do?
It gives the agent working knowledge of the Pulumi Automation API: calling Pulumi operations from code instead of the CLI, orchestrating multiple stacks, and building self-service platforms.
Local Source or Inline Source?
Local Source references an existing project via workDir, while Inline Source embeds the program in the orchestrator. Pick the first when Pulumi programs already exist and ship on their own schedule, the second when one team owns everything.
Source text
SKILL.md · Apache-2.0
---
name: pulumi-automation-api
version: 1.0.0
description: Load this skill when a user asks how to run Pulumi programmatically, embed Pulumi in an application, orchestrate multiple stacks in code, build a self-service infrastructure portal, replace pulumi CLI shell scripts with code, or use the Pulumi Automation API (LocalWorkspace, createOrSelectStack, inline programs). Also load for questions about multi-stack sequencing, parallel deployments, or passing outputs between stacks via code.
---
# Pulumi Automation API
## When to Use This Skill
Invoke this skill when:
- Orchestrating deployments across multiple Pulumi stacks
- Embedding Pulumi operations in custom applications
- Building self-service infrastructure platforms
- Replacing fragile Bash/Makefile orchestration scripts
- Creating custom CLIs for infrastructure management
- Building web applications that provision infrastructure
## What is Automation API
Automation API provides programmatic access to Pulumi operations. Instead of running `pulumi up` from the CLI, you call functions in your code that perform the same operations.
```typescript
import * as automation from "@pulumi/pulumi/automation";
// Create or select a stack
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
// Your Pulumi program here
},
});
// Run pulumi up programmatically
const upResult = await stack.up({ onOutput: console.log });
console.log(`Update summary: ${JSON.stringify(upResult.summary)}`);
```
## When to Use Automation API
### Good Use Cases
**Multi-stack orchestration:**
When you split infrastructure into multiple focused projects, Automation API helps offset the added complexity by orchestrating operations across stacks:
```text
infrastructure → platform → application
↓ ↓ ↓
(VPC) (Kubernetes) (Services)
```
Automation API ensures correct sequencing without manual intervention.
**Self-service platforms:**
Build internal tools where developers request infrastructure without learning Pulumi:
- Web portals for environment provisioning
- Slack bots that create/destroy resources
- Custom CLIs tailored to your organization
**Embedded infrastructure:**
Applications that provision their own infrastructure:
- SaaS platforms creating per-tenant resources
- Testing frameworks spinning up test environments
- CI/CD systems with dynamic infrastructure needs
**Replacing fragile scripts:**
If you have Bash scripts or Makefiles stitching together multiple `pulumi` commands, Automation API provides:
- Proper error handling
- Type safety
- Programmatic access to outputs
### When NOT to Use
- Single project with standard deployment needs
- When you don't need programmatic control over operations
## Architecture Choices
### Local Source vs Inline Source
**Local Source** - Pulumi program in separate files:
```typescript
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure", // Points to existing Pulumi project
});
```
**When to use:**
- Different teams maintain orchestrator vs Pulumi programs
- Pulumi programs already exist
- Want independent version control and release cycles
- Platform team orchestrating application team's infrastructure
**Inline Source** - Pulumi program embedded in orchestrator:
```typescript
import * as aws from "@pulumi/aws";
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
const bucket = new aws.s3.Bucket("my-bucket");
return { bucketName: bucket.id };
},
});
```
**When to use:**
- Single team owns everything
- Tight coupling between orchestration and infrastructure is desired
- Distributing as compiled binary (no source files needed)
- Simpler deployment artifact
### Language Independence
The Automation API program can use a different language than the Pulumi programs it orchestrates:
```text
Orchestrator (Go) → manages → Pulumi Program (TypeScript)
```
This enables platform teams to use their preferred language while application teams use theirs.
## Common Patterns
### Multi-Stack Orchestration
Deploy multiple stacks in dependency order:
```typescript
import * as automation from "@pulumi/pulumi/automation";
async function deploy() {
const stacks = [
{ name: "infrastructure", dir: "./infra" },
{ name: "platform", dir: "./platform" },
{ name: "application", dir: "./app" },
];
for (const stackInfo of stacks) {
console.log(`Deploying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.up({ onOutput: console.log });
console.log(`${stackInfo.name} deployed successfully`);
}
}
async function destroy() {
// Destroy in reverse order
const stacks = [
{ name: "application", dir: "./app" },
{ name: "platform", dir: "./platform" },
{ name: "infrastructure", dir: "./infra" },
];
for (const stackInfo of stacks) {
console.log(`Destroying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.selectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.destroy({ onOutput: console.log });
}
}
```
### Passing Configuration
Set stack configuration programmatically:
```typescript
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure",
});
// Set configuration values
await stack.setConfig("aws:region", { value: "us-west-2" });
await stack.setConfig("dbPassword", { value: "secret", secret: true });
// Then deploy
await stack.up();
```
### Reading Outputs
Access stack outputs after deployment:
```typescript
const upResult = await stack.up();
// Get all outputs
const outputs = await stack.outputs();
console.log(`VPC ID: ${outputs["vpcId"].value}`);
// Or from the up result
console.log(`Outputs: ${JSON.stringify(upResult.outputs)}`);
```
### Error Handling
Handle deployment failures gracefully:
```typescript
try {
const result = await stack.up({ onOutput: console.log });
if (result.summary.result === "failed") {
console.error("Deployment failed");
process.exit(1);
}
} catch (error) {
console.error(`Deployment error: ${error}`);
throw error;
}
```
### Parallel Stack Operations
When stacks are independent, deploy in parallel:
```typescript
const independentStacks = [
{ name: "service-a", dir: "./service-a" },
{ name: "service-b", dir: "./service-b" },
{ name: "service-c", dir: "./service-c" },
];
await Promise.all(independentStacks.map(async (stackInfo) => {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
return stack.up({ onOutput: (msg) => console.log(`[${stackInfo.name}] ${msg}`) });
}));
```
## Best Practices
### Separate Configuration from Code
Externalize configuration into files or environment variables:
```typescript
import * as fs from "fs";
interface DeployConfig {
stacks: Array<{ name: string; dir: string; }>;
environment: string;
}
const config: DeployConfig = JSON.parse(
fs.readFileSync("./deploy-config.json", "utf-8")
);
for (const stackInfo of config.stacks) {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: config.environment,
workDir: stackInfo.dir,
});
await stack.up();
}
```
This enables distributing compiled binaries without exposing source code.
### Stream Output for Long Operations
Use `onOutput` callback for real-time feedback:
```typescript
await stack.up({
onOutput: (message) => {
process.stdout.write(message);
// Or send to logging system, websocket, etc.
},
});
```
## Quick Reference
| Scenario | Approach |
| --- | --- |
| Existing Pulumi projects | Local source with workDir |
| New embedded infrastructure | Inline source with program function |
| Different teams | Local source for independence |
| Compiled binary distribution | Inline source or bundled local |
| Multi-stack dependencies | Sequential deployment in order |
| Independent stacks | Parallel deployment with Promise.all |
## Related Skills
- **pulumi-best-practices**: Code-level patterns for Pulumi programs
## References
- https://www.pulumi.com/docs/using-pulumi/automation-api/
- https://www.pulumi.com/docs/using-pulumi/automation-api/concepts-terminology/
- https://www.pulumi.com/blog/iac-recommended-practices-using-automation-api/
© pulumi · Apache-2.0 · pulumi/agent-skills