agentleFS
diriendirien/claude-skills/pulumi-typescript/SKILL.md

pulumi-typescript

Skill13 starsChanged 8 months agoMITView on GitHub

Scaffolds Pulumi TypeScript infrastructure-as-code projects, writes IaC code with proper resource configuration, manages Pulumi ESC environments for centralized secrets and configuration, configures OIDC authentication for cloud providers, and builds multi-language component resources. Use when the user asks to create Pulumi TypeScript projects, write Pulumi infrastructure code, set up ESC environments, configure OIDC for Pulumi, implement infrastructure automation with Node.js/TypeScript, create reusable Pulumi components, or work with stack references. Also use when the user mentions Pulumi with TypeScript, AWS/Azure/GCP infrastructure in TypeScript, or PulumiPlugin.yaml for multi-language components.

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 1

    1. dirien/yet-another-agent-harness★ 19100% same

    Edited · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository9 other files it gives its agents.

The file

Show its rules and text

We split this skill into the rules it gives an agent

22 rules. About 0 are common, 15 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈15

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  • could be automatic: a setting could enforce it
  1. Very specific:

    Instead of using pulumi config set or stack config files, use Pulumi ESC for centralized secrets and configuration.

    line 34
  2. Distinctive:

    Run any command with ESC environment variables injected:

    line 171
  3. Distinctive:

    Create components in TypeScript that can be consumed from any Pulumi language (Python, Go, C#, Java, YAML).

    line 203
  4. Very specific:

    Use pulumi.Input<T> for all scalar properties

    line 277
  5. Very specific:

    Avoid union types (string | number) - not supported

    line 278
  6. Distinctive:

    Avoid functions/callbacks - not serializable

    line 279
  7. Distinctive:

    Follow this validated workflow for safe deployments:

    line 284
  8. Distinctive:

    Check the preview output for:

    line 293
  9. Distinctive:

    If changes look incorrect, investigate the root cause before proceeding:

    line 298
  10. Distinctive:

    After successful deployment, confirm the outputs:

    line 317
  11. Very specific:

    If pulumi up fails mid-deployment:

    line 326
  12. Distinctive:

    Check the error message for the specific resource that failed

    line 327
  13. Very specific:

    Run pulumi up again — Pulumi will resume from where it left off

    line 330
  14. Very specific:

    If the stack is in an inconsistent state, use pulumi refresh to sync state with actual cloud resources

    line 331
  15. Distinctive:

    Use Pulumi ESC for all secrets - never commit secrets to stack config files

    line 336
  16. Distinctive:

    Use dynamic secrets with short TTLs when possible

    line 338
  17. Distinctive:

    Always enable server-side encryption on S3 buckets (AES256 or KMS) — this is a non-negotiable default

    line 340
  18. Distinctive:

    Use ComponentResources for reusable infrastructure patterns

    line 345
  19. Distinctive:

    Keep stack-specific config in ESC environments

    line 347
  20. Distinctive:

    Use stack references for cross-stack dependencies

    line 348
  21. Very specific:

    Always run pulumi preview before pulumi up

    line 351
  22. Distinctive:

    Use ESC environment versioning and tags for releases

    line 352

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Pulumi TypeScript Skill

Development Workflow

1. Project Setup

# Create new TypeScript project
pulumi new typescript

# Or with a cloud-specific template
pulumi new aws-typescript
pulumi new azure-typescript
pulumi new gcp-typescript

Project structure:

my-project/
├── Pulumi.yaml
├── Pulumi.dev.yaml      # Stack config (use ESC instead)
├── package.json
├── tsconfig.json
└── index.ts

2. Pulumi ESC Integration

Instead of using pulumi config set or stack config files, use Pulumi ESC for centralized secrets and configuration.

Link ESC environment to stack:

# Create ESC environment
pulumi env init myorg/myproject-dev

# Edit environment
pulumi env edit myorg/myproject-dev

# Link to Pulumi stack
pulumi config env add myorg/myproject-dev

ESC environment definition (YAML):

values:
  # Static configuration
  pulumiConfig:
    aws:region: us-west-2
    myapp:instanceType: t3.medium

  # Dynamic OIDC credentials for AWS
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789:role/pulumi-oidc
          sessionName: pulumi-deploy

  # Pull secrets from AWS Secrets Manager
  secrets:
    fn::open::aws-secrets:
      region: us-west-2
      login: ${aws.login}
      get:
        dbPassword:
          secretId: prod/database/password

  # Expose to environment variables
  environmentVariables:
    AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
    AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
    AWS_SESSION_TOKEN: ${aws.login.sessionToken}

3. TypeScript Patterns

Basic resource creation:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Get configuration from ESC
const config = new pulumi.Config();
const instanceType = config.require("instanceType");

// Create resources with proper tagging
const bucket = new aws.s3.Bucket("my-bucket", {
    versioning: { enabled: true },
    serverSideEncryptionConfiguration: {
        rule: {
            applyServerSideEncryptionByDefault: {
                sseAlgorithm: "AES256",
            },
        },
    },
    tags: {
        Environment: pulumi.getStack(),
        ManagedBy: "Pulumi",
    },
});

// Export outputs
export const bucketName = bucket.id;
export const bucketArn = bucket.arn;

Component resources for reusability:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

interface WebServiceArgs {
    port: pulumi.Input<number>;
    imageUri: pulumi.Input<string>;
}

class WebService extends pulumi.ComponentResource {
    public readonly url: pulumi.Output<string>;

    constructor(name: string, args: WebServiceArgs, opts?: pulumi.ComponentResourceOptions) {
        super("custom:app:WebService", name, {}, opts);

        // Create child resources with { parent: this }
        const lb = new aws.lb.LoadBalancer(`${name}-lb`, {
            loadBalancerType: "application",
            // ... configuration
        }, { parent: this });

        this.url = lb.dnsName;
        this.registerOutputs({ url: this.url });
    }
}

Stack references for cross-stack dependencies:

import * as pulumi from "@pulumi/pulumi";

// Reference outputs from networking stack
const networkingStack = new pulumi.StackReference("myorg/networking/prod");
const vpcId = networkingStack.getOutput("vpcId");
const subnetIds = networkingStack.getOutput("privateSubnetIds");

Working with Outputs:

import * as pulumi from "@pulumi/pulumi";

// Use apply for transformations
const uppercaseName = bucket.id.apply(id => id.toUpperCase());

// Use pulumi.all for multiple outputs
const combined = pulumi.all([bucket.id, bucket.arn]).apply(
    ([id, arn]) => `Bucket ${id} has ARN ${arn}`
);

// Conditional resources
const isProd = pulumi.getStack() === "prod";
const monitoring = isProd ? new aws.cloudwatch.MetricAlarm("alarm", {
    // ... configuration
}) : undefined;

4. Using ESC with pulumi env run

Run any command with ESC environment variables injected:

# Run pulumi commands with ESC credentials
pulumi env run myorg/aws-dev -- pulumi up

# Run tests with secrets
pulumi env run myorg/test-env -- npm test

# Open environment and export to shell
pulumi env open myorg/myproject-dev --format shell

5. Async Patterns

// Export async function for top-level await
export = async () => {
    const data = await fetchExternalData();

    const resource = new aws.s3.Bucket("bucket", {
        tags: { data: data.value },
    });

    return {
        bucketName: resource.id,
    };
};

6. Multi-Language Components

Create components in TypeScript that can be consumed from any Pulumi language (Python, Go, C#, Java, YAML).

Project structure for multi-language component:

my-component/
├── PulumiPlugin.yaml      # Required for multi-language
├── package.json
├── tsconfig.json
└── index.ts               # Component definition

PulumiPlugin.yaml:

runtime: nodejs

Component with proper Args interface:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

// Args interface - use Input types for all properties
export interface SecureBucketArgs {
    // Wrap all scalar members in Input types
    bucketName: pulumi.Input<string>;
    enableVersioning?: pulumi.Input<boolean>;
    tags?: pulumi.Input<Record<string, pulumi.Input<string>>>;
}

export class SecureBucket extends pulumi.ComponentResource {
    public readonly bucketId: pulumi.Output<string>;
    public readonly bucketArn: pulumi.Output<string>;

    // Constructor must have 'args' parameter with type annotation
    constructor(name: string, args: SecureBucketArgs, opts?: pulumi.ComponentResourceOptions) {
        super("myorg:storage:SecureBucket", name, {}, opts);

        const bucket = new aws.s3.Bucket(`${name}-bucket`, {
            bucket: args.bucketName,
            versioning: { enabled: args.enableVersioning ?? true },
            serverSideEncryptionConfiguration: {
                rule: {
                    applyServerSideEncryptionByDefault: {
                        sseAlgorithm: "AES256",
                    },
                },
            },
            tags: args.tags,
        }, { parent: this });

        this.bucketId = bucket.id;
        this.bucketArn = bucket.arn;

        this.registerOutputs({
            bucketId: this.bucketId,
            bucketArn: this.bucketArn,
        });
    }
}

Publishing for multi-language consumption:

# Consume from git repository
pulumi package add github.com/myorg/my-component

# With version tag
pulumi package add github.com/myorg/my-component@v1.0.0

# Local development
pulumi package add /path/to/local/my-component

Multi-language Args requirements:

  • Use pulumi.Input<T> for all scalar properties
  • Avoid union types (string | number) - not supported
  • Avoid functions/callbacks - not serializable
  • Constructor must have args parameter with type declaration

Deployment Workflow with Validation

Follow this validated workflow for safe deployments:

1. Preview Changes

pulumi preview

Review the output to understand what resources will be created, modified, or deleted.

2. Validate Changes

Check the preview output for:

  • Unexpected resource deletions or modifications
  • Correct number and type of resources
  • Proper configuration values (region, instance type, tags, etc.)

If changes look incorrect, investigate the root cause before proceeding:

# Check current stack state
pulumi stack output

# Review ESC environment values
pulumi env open myorg/myproject-dev

# Verify configuration
pulumi config

3. Deploy

Once validated, deploy the changes:

pulumi up

4. Verify Outputs

After successful deployment, confirm the outputs:

pulumi stack output

Compare outputs against expected values (e.g., bucket names, endpoint URLs, resource IDs).

Error Recovery

If pulumi up fails mid-deployment:

  1. Check the error message for the specific resource that failed
  2. Review resource configuration and ESC environment values
  3. Fix the underlying issue (e.g., IAM permissions, invalid configuration)
  4. Run pulumi up again — Pulumi will resume from where it left off
  5. If the stack is in an inconsistent state, use pulumi refresh to sync state with actual cloud resources

Best Practices

Security

  • Use Pulumi ESC for all secrets - never commit secrets to stack config files
  • Enable OIDC authentication instead of static credentials
  • Use dynamic secrets with short TTLs when possible
  • Apply least-privilege IAM policies
  • Always enable server-side encryption on S3 buckets (AES256 or KMS) — this is a non-negotiable default
  • Block public access on S3 buckets unless explicitly required
  • Enable versioning on storage resources for data protection

Code Organization

  • Use ComponentResources for reusable infrastructure patterns
  • Leverage TypeScript's type system for configuration validation
  • Keep stack-specific config in ESC environments
  • Use stack references for cross-stack dependencies

Deployment

  • Always run pulumi preview before pulumi up
  • Use ESC environment versioning and tags for releases
  • Implement proper tagging strategy for all resources

Common Commands

# Environment Commands (pulumi env)
pulumi env init <org>/<project>/<env>        # Create environment
pulumi env edit <org>/<env>                  # Edit environment
pulumi env open <org>/<env>                  # View resolved values
pulumi env run <org>/<env> -- <command>      # Run with env vars
pulumi env version tag <org>/<env> <tag>     # Tag version

# Pulumi Commands
pulumi new typescript                  # New project
pulumi config env add <org>/<env>     # Link ESC environment
pulumi preview                         # Preview changes
pulumi up                              # Deploy
pulumi stack output                    # View outputs
pulumi destroy                         # Tear down
pulumi refresh                         # Sync state with cloud

References

  • references/pulumi-esc.md - ESC patterns and commands
  • references/pulumi-patterns.md - Common infrastructure patterns
  • references/pulumi-typescript.md - TypeScript-specific guidance
  • references/pulumi-best-practices-aws.md - AWS best practices
  • references/pulumi-best-practices-azure.md - Azure best practices
  • references/pulumi-best-practices-gcp.md - GCP best practices

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.