Skip to content

Connect Pulumi to AI Agents: Automate Secret Ops and Cloud Resources

Uday Gajavalli Uday Gajavalli 11 min read AI & Agents
TrutoFor teams building AI agents

Give your AI agent Pulumi tools.

Connecting Pulumi to AI agents requires strict schema adherence and state management. This guide shows how to bypass building custom integrations by using Truto's /tools endpoint to fetch AI-ready tools, bind them natively to LLM frameworks, and safely automate complex infrastructure workflows.

In this guide

  1. 01Fetch Pulumi Tools from Truto
  2. 02Bind Tools to the LLM
  3. 03Execute the Agent Loop
  4. 04Handle State and Rate Limits

The guide

Learn how to connect Pulumi to AI agents using Truto's /tools endpoint. Build autonomous workflows for drift detection, secret rotation, and stack updates.

You want to connect Pulumi Cloud to an AI agent so your system can autonomously detect infrastructure drift, execute stack updates, rotate environment secrets, and enforce compliance policies. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom Pulumi API integration from scratch.

Infrastructure as Code (IaC) APIs are inherently stateful and unforgiving. When you give a Large Language Model (LLM) read and write access to your Pulumi Cloud instance, it cannot afford to hallucinate API payloads, mismanage URNs, or guess at nested JSON structures. If your team uses ChatGPT, check out our guide on connecting Pulumi to ChatGPT, or if you are building on Anthropic's models, read our guide to connecting Pulumi to Claude. For developers building custom autonomous workflows, you need a programmatic way to fetch these tools and bind them natively to your agent framework.

Building an AI agent is a straightforward exercise in prompting and orchestration. Giving that agent reliable access to complex cloud infrastructure APIs is where projects stall. If you decide to build a custom connector, you own the entire API lifecycle. You must write the JSON schemas for the LLM to understand the endpoints, handle the OAuth or Personal Access Token (PAT) lifecycle, normalize pagination cursors, and safely parse deeply nested infrastructure graphs.

This guide breaks down exactly how to fetch AI-ready tools for Pulumi Cloud, bind them to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex SecOps and DevOps workflows. For a broader look at this design pattern across multiple SaaS applications, read our research on Architecting AI Agents: LangGraph, LangChain, and the SaaS Integration Bottleneck.

The Engineering Reality of the Pulumi Cloud API

Giving an LLM access to external data sounds simple in a prototype. You write a Node.js function that makes a fetch request to Pulumi and wrap it in an @tool decorator. In production against complex infrastructure systems, this approach collapses.

Pulumi Cloud's REST API introduces several specific integration challenges that break standard agent assumptions. If you hardcode these interactions into your agent, you will spend your sprints writing defensive integration code instead of improving your model's reasoning capabilities.

The URN Encoding Trap

Cloud resources in Pulumi Insights are uniquely identified by their Uniform Resource Name (URN). A Pulumi URN is a long, highly structured string that includes the project, stack, cloud provider, resource type, and resource name (e.g., urn:pulumi:prod::my-project::aws:s3/bucket:Bucket::my-bucket).

When querying relationships or policy violations tied to a specific resource, the Pulumi API often requires this URN to be passed as a path parameter or query parameter in the format resource_type_and_id. Crucially, Pulumi requires this value to be double-URL-encoded (e.g., replacing :: with %253A%253A). If you give an LLM raw access to a standard fetch tool, it will naturally pass the literal string or single-encode it. The API will reject the call with a 400 Bad Request. You must abstract this encoding requirement away from the model's context window.

State Lock Conflicts and Concurrency

Unlike a standard CRM where updating a record is a simple PATCH request, infrastructure operations are durably stateful. If an agent wants to apply a proposed change request or run a drift remediation update, it must interact with the stack's state lock.

If the agent attempts to call create_a_pulumi_begin_update while another user or CI/CD pipeline is currently running an update, the API will return an HTTP 409 Conflict. Standard LLMs handle this poorly - they often assume a transient network failure and enter an infinite retry loop, burning tokens and spamming the API. The integration layer must cleanly map state conflict errors into actionable feedback for the agent, explicitly instructing it to wait or abort.

Environment, Secrets, and Configuration (ESC) Nesting

Pulumi ESC environments are defined using raw YAML payloads or heavily nested JSON structures that contain imports, static values, provider configurations, and function invocations (like fn::secret or fn::open).

If you instruct an agent to "add a secret to the production environment," it might attempt to send a flat JSON patch. Pulumi ESC requires a completely valid, full-document representation to update the environment definition (update_a_pulumi_env_by_id). It also requires strict schema compliance for encryption (create_a_pulumi_encrypt_secret). Exposing the raw HTTP mechanics of ESC to the agent guarantees malformed YAML errors.

Why a Unified Tool Layer Matters for Agent Safety

Direct API tools (one bespoke function per raw Pulumi endpoint) look convenient, but they push provider quirks directly into the LLM's context. The model has to remember double URL encoding, manual pagination logic, and exact YAML shapes.

Using Truto's proxy APIs via the /tools endpoint collapses these complexities behind a standardized, pre-validated interface. Your agent sees create_a_pulumi_draft, list_all_pulumi_drift_status, and create_a_pulumi_rotate mapped to strict JSON schemas. That gives you three concrete safety wins:

  1. Smaller attack surface for hallucination. The LLM only chooses from defined function names and is forced to provide arguments matching the schema. Invalid arguments are rejected locally before they even hit the Pulumi API.
  2. Normalized Authentication and Pagination. Truto handles the underlying token lifecycle and pagination cursors. The agent simply requests data, and Truto returns the normalized result.
  3. Real-Time Schema Updates. As Pulumi adds new fields to their API, Truto's proxy layer updates automatically. You do not need to redeploy your agent's codebase to access a new capability.

Handling the Physics of the API: Rate Limits

When building autonomous agents that can loop over infrastructure data (e.g., checking drift status across 500 stacks), you will inevitably hit the Pulumi Cloud API rate limits.

Factual note on rate limit architecture: Truto acts as a transparent proxy for API execution. Truto does not automatically retry, throttle, or apply exponential backoff on rate limit errors. When Pulumi returns an HTTP 429 Too Many Requests, Truto passes that error directly back to the caller.

However, Truto normalizes the upstream rate limit information into standardized IETF headers, regardless of how the underlying provider formats them. You will receive:

  • ratelimit-limit: The total requests allowed in the current window.
  • ratelimit-remaining: How many requests you have left.
  • ratelimit-reset: The timestamp when the quota resets.

The caller (your agent framework or execution loop) is completely responsible for catching the 429 status, reading the ratelimit-reset header, and pausing the agent's execution. Do not build agents that assume the integration layer will magically absorb heavy looping traffic.

High-Leverage Pulumi Tools for AI Agents

Truto exposes the entirety of the Pulumi Cloud API as LLM tools. Instead of overwhelming your agent with hundreds of endpoints, you filter the /tools response to provide only the high-leverage operations required for a specific workflow.

Here are six hero tools that enable critical infrastructure operations.

Check Stack Drift Status

Infrastructure drift occurs when cloud resources are modified outside of Pulumi. This tool queries the current drift detection status of a stack.

Tool: list_all_pulumi_drift_status

Usage notes: Requires the organization name, project name, and stack name. Returns a structured status indicating whether drift was detected, when the last check ran, and the specific resource differences.

"Check the 'prod-db-cluster' stack in the 'core-infra' project for drift. Give me a summary of any resources that differ from their desired state."

Begin Stack Update

This tool initiates a standard pulumi up via Pulumi Deployments. It is the primary mechanism for executing infrastructure changes.

Tool: create_a_pulumi_begin_update

Usage notes: This is a highly privileged operation. It requires an active Pulumi Deployments configuration on the stack. The LLM must supply the exact stack coordinates. Because it initiates an async deployment, the agent should subsequently poll the deployment status if it needs to report final success.

"The drift report shows manual changes to the S3 bucket tags. Start a stack update on 'prod-db-cluster' to revert the manual changes and reconcile the state."

Audit Policy Violations

Pulumi CrossGuard enforces compliance rules across your infrastructure. This tool fetches the active policy violations detected during continuous compliance scans or stack updates.

Tool: list_all_pulumi_policyresults_issues

Usage notes: Returns detailed violation records, including the non-compliant resource URN, the specific policy rule broken, enforcement level (advisory vs. mandatory), and current triage status.

"List all mandatory policy violations across our organization. Filter for any issues related to 'public-s3-buckets' or 'missing-encryption' and output them into a summary table."

Encrypt Environment Secrets

Pulumi ESC manages secrets for stacks and applications. This tool allows the agent to safely encrypt plaintext into ciphertext using the environment's configured encryption key.

Tool: create_a_pulumi_encrypt_secret

Usage notes: The agent passes plaintext values to this tool. The Pulumi API returns the encrypted fn::secret values. The agent can then use these ciphertexts to safely construct a draft environment update without leaking plaintext in subsequent logs.

"Take this new database password, encrypt it using the 'prod-secrets' ESC environment key, and return the ciphertext payload so I can update the configuration."

Propose Environment Changes (Drafts)

Instead of applying changes directly, this tool creates a draft change request proposing modifications to a Pulumi ESC environment, kicking off an approval workflow.

Tool: create_a_pulumi_draft

Usage notes: Requires the Approvals feature to be enabled on the organization. This allows the agent to act as a secure recommender system - drafting changes that human administrators must approve.

"Draft a change request for the 'staging-api-config' environment. Update the 'log_level' value from 'INFO' to 'DEBUG' and submit the draft."

Query the Infrastructure Graph

Pulumi Insights maintains a searchable graph of all deployed resources across your organization. This tool executes a graph query to find resources, relationships, and dependencies.

Tool: create_a_pulumi_graph_query

Usage notes: The query must follow the specific Pulumi Insights graph schema. This is incredibly powerful for cross-stack blast radius analysis.

"Run a graph query to find all AWS EC2 instances in the organization that are associated with the 'frontend-cluster' security group, regardless of which stack manages them."

Workflows in Action

Providing an agent with isolated tools is just the foundation. The real value is unlocked when the agent chains these operations together to execute multi-step personas.

1. The Autonomous DevOps Auditor

DevOps teams spend hours manually checking stacks for drift and resolving minor discrepancies. An agent can automate this reconciliation loop.

"Audit the 'payment-gateway' project. Check all stacks for drift. If you find any minor tag drift, start an update to reconcile it. If you find resource deletion drift, alert me and do not update."

Execution Steps:

  1. The agent calls list_all_pulumi_user_stacks (filtered by the project) to get the list of target stacks.
  2. It iterates over the stacks, calling list_all_pulumi_drift_status for each.
  3. It analyzes the returned drift details. If the drift only involves tags, it calls create_a_pulumi_begin_update to run a reconciliation deployment.
  4. If it detects severe drift (e.g., a dropped database table), it skips the update and generates a summarized incident report for the human operator.

2. The Zero-Trust SecOps Remediator

When a secret is compromised, rotating it across multiple environments and stacks is a race against time. An agent can orchestrate the rotation and application securely.

"We had a potential credential leak. Immediately rotate the 'stripe-api-key' secret in the 'prod-billing' ESC environment and apply the change."

Execution Steps:

  1. The agent calls create_a_pulumi_rotate targeting the specific path (stripe-api-key) in the ESC environment. This triggers Pulumi ESC's native secret rotators to issue a new key from the external provider.
  2. The agent calls create_a_pulumi_draft to capture the new rotated state.
  3. The agent leverages create_a_pulumi_apply to apply the draft environment changes, ensuring all downstream applications fetching config from ESC instantly receive the rotated credential.

3. The Compliance Analyst

Security teams need continuous visibility into policy violations, but pulling these reports manually is tedious.

"Find all stacks with active policy violations. Filter for 'High' severity issues related to IAM permissions. Format the output as a Markdown table including the stack name, the specific resource URN, and the remediation status."

Execution Steps:

  1. The agent calls list_all_pulumi_policyresults_issues with filters applied for 'High' severity.
  2. The agent processes the JSON array of violations, extracting the URNs and stack associations.
  3. It formats the data into a clean Markdown table in the chat interface, giving the security team an immediate, actionable hit-list.

Building Multi-Step Workflows

To build these workflows, you need to bind Truto's proxy tools to your LLM execution loop. Truto's /tools endpoint serves the schema. Frameworks like LangChain, LangGraph, or the Vercel AI SDK consume it.

Here is a complete architectural look at how to fetch the tools, bind them to an agent, and execute a loop while properly handling Truto's rate limit headers.

sequenceDiagram
    participant App as Application
    participant Agent as AI Agent (LangChain)
    participant Truto as Truto Proxy Layer
    participant Pulumi as Pulumi Cloud API

    App->>Truto: GET /integrated-account/<id>/tools
    Truto-->>App: JSON Schemas for Pulumi Methods
    App->>Agent: Bind schemas using .bindTools()
    App->>Agent: Prompt: "Check stack drift"
    Agent->>Truto: Execute list_all_pulumi_drift_status
    Truto->>Pulumi: GET /api/stacks/.../drift
    Pulumi-->>Truto: 200 OK (Drift found)
    Truto-->>Agent: Return Tool Result
    Agent->>Truto: Execute create_a_pulumi_begin_update
    Truto->>Pulumi: POST /api/stacks/.../update
    Pulumi-->>Truto: 429 Too Many Requests
    Truto-->>Agent: 429 Error + ratelimit-reset header
    Note over App,Agent: App catches 429, parses header,<br>sleeps until reset, then retries.
    Agent->>Truto: Retry create_a_pulumi_begin_update
    Truto->>Pulumi: POST /api/stacks/.../update
    Pulumi-->>Truto: 202 Accepted
    Truto-->>Agent: Return Tool Result
    Agent-->>App: Final response: "Drift remediated"

The following TypeScript example uses truto-langchainjs-toolset to execute this pattern natively. Note the explicit error handling for HTTP 429 rate limits, adhering to the physical constraints of the upstream API.

import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "truto-langchainjs-toolset";
import { HumanMessage } from "@langchain/core/messages";
 
async function runPulumiAgent() {
  // 1. Initialize the LLM
  const model = new ChatOpenAI({ 
    modelName: "gpt-4o",
    temperature: 0
  });
 
  // 2. Fetch Pulumi tools via Truto
  // We filter for specific methods to keep the context window tight
  const toolManager = new TrutoToolManager({
    trutoApiKey: process.env.TRUTO_API_KEY,
    integratedAccountId: process.env.PULUMI_ACCOUNT_ID,
    filters: {
      methods: ["read", "custom", "write"] 
    }
  });
 
  const tools = await toolManager.getTools();
  console.log(`Loaded ${tools.length} Pulumi tools.`);
 
  // 3. Bind tools to the model
  const modelWithTools = model.bindTools(tools);
 
  // 4. Create the execution loop with rate limit backoff
  let messages = [new HumanMessage("Check the 'core-infra' stack for drift. If drifted, begin an update.")];
  
  while (true) {
    const response = await modelWithTools.invoke(messages);
    messages.push(response);
 
    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log("Agent finished:", response.content);
      break;
    }
 
    // Execute tool calls sequentially to manage state locks properly
    for (const toolCall of response.tool_calls) {
      console.log(`Executing: ${toolCall.name}`);
      const tool = tools.find(t => t.name === toolCall.name);
      
      let success = false;
      let retries = 0;
      const maxRetries = 3;
 
      while (!success && retries < maxRetries) {
        try {
          const result = await tool.invoke(toolCall.args);
          messages.push({
            role: "tool",
            tool_call_id: toolCall.id,
            name: toolCall.name,
            content: result
          });
          success = true;
 
        } catch (error) {
          // Truto passes 429s directly. We MUST handle them.
          if (error.response && error.response.status === 429) {
            const resetTime = error.response.headers.get('ratelimit-reset');
            const sleepSeconds = resetTime ? 
                Math.max(1, parseInt(resetTime) - Math.floor(Date.now() / 1000)) : 
                Math.pow(2, retries); // Fallback exponential backoff
            
            console.warn(`Rate limited. Sleeping for ${sleepSeconds} seconds...`);
            await new Promise(resolve => setTimeout(resolve, sleepSeconds * 1000));
            retries++;
          } else {
             // Pass non-rate-limit errors (like 409 State Conflicts) back to the LLM to reason about
             messages.push({
                role: "tool",
                tool_call_id: toolCall.id,
                name: toolCall.name,
                content: `Error executing tool: ${error.message}`
             });
             success = true; // Breaking the retry loop, letting LLM handle the failure
          }
        }
      }
    }
  }
}
 
runPulumiAgent().catch(console.error);

Moving Beyond the Integration Bottleneck

Writing defensive scripts to encode URNs, wrangle YAML schemas, and manage authentication state takes engineering cycles away from building intelligent agent capabilities.

By leveraging a unified proxy layer, your architecture shifts from maintaining brittle API connectors to orchestrating pure logic. Truto handles the schema translation and token lifecycle, giving your LLM deterministic, safe access to the entirety of Pulumi Cloud.

Two ways to put Pulumi to work

Truto

For product teams

Give your agent Pulumi tools

Your customers connect their own Pulumi accounts. Your product gets one API and MCP tools for Pulumi, through Truto.

FAQ

How do AI agents handle Pulumi state lock conflicts?
When an agent attempts a stack update on a locked stack, Pulumi returns an HTTP 409 Conflict. The agent must catch this error, read the conflict diagnostic, and either wait for the lock to release or alert a human operator instead of endlessly retrying.
Does Truto automatically retry Pulumi API rate limit errors?
No. Truto normalizes upstream rate limit info into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) but does not retry, throttle, or apply backoff. The caller framework must handle the HTTP 429 response and apply its own retry logic.
Which agent frameworks can I use with Truto Pulumi tools?
Truto's /tools endpoint returns standard JSON Schemas that can be converted to function definitions for any framework, including LangChain, LangGraph, CrewAI, Vercel AI SDK, or custom execution loops.
Can an agent securely encrypt secrets in Pulumi ESC?
Yes. By using the create_a_pulumi_encrypt_secret tool, an agent can pass plaintext to Pulumi Cloud to receive ciphertext. The plaintext is never stored in Truto's proxy layer, allowing the agent to securely write encrypted values back to the ESC environment YAML.
Pulumi PulumiAI agent tools Get a sandbox

More from our Blog