# Pulumi Automation Api

> Load this skill when a user asks how to run Pulumi programmatically, embed Pulumi in an application, orchestrate multiple stacks in code, build a self-service infrastructure portal, replace pulumi CLI shell scripts with code, or use the Pulumi Automation API (LocalWorkspace, createOrSelectStack, inline programs). Also load for questions about multi-stack sequencing, parallel deployments, or passi…

- **Type:** Skill
- **Install:** `agentstack add skill-pulumi-agent-skills-pulumi-automation-api`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [pulumi](https://agentstack.voostack.com/s/pulumi)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [pulumi](https://github.com/pulumi)
- **Source:** https://github.com/pulumi/agent-skills/tree/main/pulumi/skills/pulumi-automation-api

## Install

```sh
agentstack add skill-pulumi-agent-skills-pulumi-automation-api
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 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;
    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/

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [pulumi](https://github.com/pulumi)
- **Source:** [pulumi/agent-skills](https://github.com/pulumi/agent-skills)
- **License:** Apache-2.0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** yes
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-pulumi-agent-skills-pulumi-automation-api
- Seller: https://agentstack.voostack.com/s/pulumi
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
