Skip to main content
MindStudio
Pricing
Blog About
My Workspace

How to Use the Claude Agent SDK to Deploy Agentic Workflows to Modal or Trigger.dev

The Claude Agent SDK gives you Claude Code's full tool loop as an API endpoint. Learn how to deploy it to Modal or Trigger.dev for serverless agent execution.

MindStudio Team RSS
How to Use the Claude Agent SDK to Deploy Agentic Workflows to Modal or Trigger.dev

What the Claude Agent SDK Actually Gives You

Anthropic’s Claude Code has always been impressive as an interactive terminal tool. But the Claude Agent SDK changes the equation — it exposes Claude Code’s full agent loop as a programmable API you can call from your own code, trigger via webhooks, or deploy to a serverless platform.

That’s a meaningful shift. Instead of sitting in a terminal watching Claude work, you can wire it into automated pipelines, background job queues, and production infrastructure. Deploying the Claude Agent SDK to Modal or Trigger.dev is one of the most practical ways to do that — and the workflow patterns you build here apply across virtually any agentic use case.

This guide walks through both deployment paths end to end: what each platform brings to the table, how to configure the SDK for each, and what to watch out for when running long-horizon agents in serverless environments.


What the Claude Agent SDK Is (and Isn’t)

The Claude Agent SDK (@anthropic-ai/claude-code) is a Node.js package that gives you programmatic access to the same agent loop Claude Code runs in your terminal. That includes:

  • Tool invocation — bash execution, file system reads and writes, web search
  • Multi-turn reasoning — the model plans, acts, observes results, and continues until the task is complete
  • Structured output streaming — events come back as an async generator, so you can handle each step, log intermediate results, or pipe output downstream
REMY IS NOT
  • a coding agent
  • no-code
  • vibe coding
  • a faster Cursor
IT IS
a general contractor for software

The one that tells the coding agents what to build.

What it isn’t: a simple chat completion API. You’re not calling Claude once and getting a single response. You’re running a stateful agent session that may take dozens of model calls, tool uses, and self-corrections to finish a task. That has real implications for how you deploy it.

The Core query() Function

The SDK’s primary interface is the query() function:

import { query } from "@anthropic-ai/claude-code";

const messages = [];

for await (const event of query({
  prompt: "Analyze the error logs in /var/log/app.log and suggest fixes",
  options: {
    allowedTools: ["bash", "read_file"],
    maxTurns: 20,
  },
})) {
  messages.push(event);
  console.log(event);
}

Each iteration of the loop yields a structured event — a tool call, a model response, a result, or a completion signal. You have full visibility into what the agent is doing at each step.

Why This Needs Serverless Infrastructure

Running an agent session is not like serving an HTTP request. A typical agentic task might run for 2 to 15 minutes, involve unpredictable compute bursts, and need to be invoked from external systems (webhooks, cron jobs, other services).

Local execution works fine for development, but in production you need:

  • Long execution timeouts — most serverless functions cap at 30 seconds or a few minutes; agent workloads can run much longer
  • Scalable concurrency — you might need to run dozens of agent sessions in parallel
  • Observability — logs, traces, retries, and failure visibility
  • Triggering from external events — webhooks, queues, schedules

That’s exactly what Modal and Trigger.dev are built for.


Deploying the Claude Agent SDK to Modal

Modal is a serverless compute platform focused on Python. It’s particularly popular for ML workloads, but it handles any long-running compute job well. Its key advantage for agent deployments is flexible execution time limits and straightforward scaling.

Prerequisites

  • A Modal account and the Modal CLI installed (pip install modal)
  • ANTHROPIC_API_KEY available as a Modal secret
  • Node.js available in your Modal image (or use a prebuilt image that includes it)

Setting Up the Modal App

Modal uses Python decorators to define functions and configure their runtime. Here’s a basic setup for running Claude agent sessions:

import modal
import subprocess
import json

app = modal.App("claude-agent")

# Define the image with Node.js and the Claude SDK installed
image = (
    modal.Image.debian_slim()
    .apt_install("nodejs", "npm")
    .run_commands("npm install -g @anthropic-ai/claude-code")
)

@app.function(
    image=image,
    secrets=[modal.Secret.from_name("anthropic-key")],
    timeout=900,  # 15 minutes — adjust for your use case
    memory=1024,
)
def run_agent_task(prompt: str, allowed_tools: list[str] = None) -> dict:
    import os
    
    script = f"""
    const {{ query }} = require('@anthropic-ai/claude-code');
    
    async function run() {{
        const events = [];
        for await (const event of query({{
            prompt: {json.dumps(prompt)},
            options: {{
                allowedTools: {json.dumps(allowed_tools or ['bash', 'read_file', 'write_file'])},
                maxTurns: 30,
            }}
        }})) {{
            events.push(event);
        }}
        console.log(JSON.stringify({{ events }}));
    }}
    
    run().catch(err => {{
        console.error(JSON.stringify({{ error: err.message }}));
        process.exit(1);
    }});
    """
    
    result = subprocess.run(
        ["node", "-e", script],
        capture_output=True,
        text=True,
        env={**os.environ},
    )
    
    if result.returncode != 0:
        raise RuntimeError(f"Agent failed: {result.stderr}")
    
    return json.loads(result.stdout)

Exposing the Agent as a Web Endpoint

Modal lets you attach an HTTP endpoint to any function with a single decorator. This turns your agent into a callable API:

@app.function(
    image=image,
    secrets=[modal.Secret.from_name("anthropic-key")],
    timeout=900,
)
@modal.web_endpoint(method="POST")
def agent_endpoint(request: dict) -> dict:
    prompt = request.get("prompt", "")
    tools = request.get("tools", ["bash", "read_file"])
    return run_agent_task.remote(prompt, tools)

Deploy with modal deploy agent.py and Modal gives you a public HTTPS URL you can POST to. No infrastructure setup, no container management.

Scheduling Agent Tasks in Modal

For agents that should run on a schedule — a daily code audit, a weekly report generation task — Modal’s @app.schedule decorator handles this cleanly:

@app.function(
    image=image,
    secrets=[modal.Secret.from_name("anthropic-key")],
    timeout=900,
    schedule=modal.Cron("0 9 * * 1"),  # Every Monday at 9am UTC
)
def weekly_code_review():
    return run_agent_task.remote(
        prompt="Review all Python files modified in the last 7 days. Flag any security issues, performance problems, or dead code.",
        allowed_tools=["bash", "read_file", "list_directory"]
    )

What Modal Is Good At

  • Arbitrary runtimes — you control the container, so you can run Node, Python, Rust, or anything else
  • GPU access — useful if your agent pipeline involves local model inference
  • Parallel execution — Modal scales function invocations horizontally with minimal config
  • Simple pricing — pay per second of compute, no idle costs

Deploying the Claude Agent SDK to Trigger.dev

Trigger.dev is a background job platform with a TypeScript-first SDK. It’s purpose-built for tasks that need long execution windows, retry logic, real-time progress logging, and triggering from webhooks or events.

For Claude agent deployments, Trigger.dev v3 is particularly useful because it natively supports tasks that run for up to an hour, has built-in concurrency controls, and makes it straightforward to connect agent runs to external triggers like GitHub webhooks, Stripe events, or custom API calls.

Prerequisites

  • A Trigger.dev account and project
  • @trigger.dev/sdk and @anthropic-ai/claude-code installed in your project
  • ANTHROPIC_API_KEY set in your Trigger.dev environment variables

Defining a Trigger.dev Task

Trigger.dev v3 tasks are defined with the task function from the SDK:

import { task, logger } from "@trigger.dev/sdk/v3";
import { query } from "@anthropic-ai/claude-code";

export const runClaudeAgent = task({
  id: "run-claude-agent",
  maxDuration: 600, // 10 minutes in seconds
  retry: {
    maxAttempts: 2,
    factor: 2,
  },
  run: async (payload: {
    prompt: string;
    allowedTools?: string[];
  }) => {
    const { prompt, allowedTools = ["bash", "read_file", "write_file"] } = payload;
    
    logger.info("Starting Claude agent session", { prompt });
    
    const results = [];
    let turnCount = 0;
    
    for await (const event of query({
      prompt,
      options: {
        allowedTools,
        maxTurns: 25,
      },
    })) {
      turnCount++;
      results.push(event);
      
      // Log progress to Trigger.dev's dashboard in real time
      if (event.type === "tool_use") {
        logger.info(`Tool call: ${event.name}`, { input: event.input });
      }
      
      if (event.type === "assistant") {
        logger.info("Agent response received", { turnCount });
      }
    }
    
    logger.info("Agent session complete", { totalTurns: turnCount });
    
    return {
      success: true,
      events: results,
      turns: turnCount,
    };
  },
});

Triggering from a Webhook

Trigger.dev makes it simple to fire agent tasks from incoming webhooks. Here’s a setup that launches an agent when a GitHub PR is opened:

import { task, logger } from "@trigger.dev/sdk/v3";
import { runClaudeAgent } from "./tasks/claude-agent";

export const onPullRequestOpened = task({
  id: "pr-code-review",
  run: async (payload: {
    prNumber: number;
    repoUrl: string;
    diff: string;
  }) => {
    logger.info("PR opened, starting code review", { prNumber: payload.prNumber });
    
    const result = await runClaudeAgent.triggerAndWait({
      prompt: `Review this pull request diff and provide structured feedback on:
        1. Security vulnerabilities
        2. Performance issues
        3. Code style and readability
        4. Test coverage gaps
        
        Diff:
        ${payload.diff}
        
        Format your response as JSON with keys: security, performance, style, tests`,
      allowedTools: ["bash"],
    });
    
    return result;
  },
});

Other agents start typing. Remy starts asking.

YOU SAID "Build me a sales CRM."
01 DESIGN Should it feel like Linear, or Salesforce?
02 UX How do reps move deals — drag, or dropdown?
03 ARCH Single team, or multi-org with permissions?

Scoping, trade-offs, edge cases — the real work. Before a line of code.

Scheduled Agents in Trigger.dev

For recurring agent tasks, Trigger.dev supports cron scheduling directly in your task definition:

import { schedules } from "@trigger.dev/sdk/v3";
import { runClaudeAgent } from "./tasks/claude-agent";

export const dailyAudit = schedules.task({
  id: "daily-security-audit",
  cron: "0 8 * * *", // 8am UTC daily
  run: async () => {
    return await runClaudeAgent.triggerAndWait({
      prompt: "Scan all configuration files for exposed secrets, deprecated dependencies, or misconfigured permissions. Output a prioritized list of findings.",
      allowedTools: ["bash", "read_file", "list_directory"],
    });
  },
});

What Trigger.dev Is Good At

  • TypeScript-native — the entire SDK is typed, which pairs naturally with the Claude SDK’s TypeScript output
  • Real-time logging — every logger.info() call appears in the Trigger.dev dashboard instantly, giving you visibility into what the agent is doing mid-run
  • Event-driven triggers — connect directly to webhooks from GitHub, Stripe, Slack, or custom sources without writing any glue code
  • Retry and failure handling — built-in exponential backoff and failure alerts, critical for production agent workloads
  • Concurrency limits — prevent agent sessions from overwhelming your API quota

Both platforms handle Claude agent deployments well, but they have different strengths.

FactorModalTrigger.dev
Primary languagePythonTypeScript
Execution timeoutUp to 24 hoursUp to 1 hour (v3)
GPU supportYesNo
Real-time loggingBasicFull dashboard
Event-driven triggersVia web endpointsNative integrations
Pricing modelPer-second computePer task run
SchedulingBuilt-in cronBuilt-in cron
Best forPython teams, GPU workloads, custom runtimesTypeScript teams, event-driven pipelines, rich observability

Choose Modal if:

  • Your team works primarily in Python
  • You need GPU access at any point in the pipeline
  • You want maximum control over the execution environment
  • Your agent tasks run longer than an hour

Choose Trigger.dev if:

  • You’re already in a TypeScript/Node.js stack
  • You need tight webhook integration with external services
  • You want real-time visibility into agent progress from a dashboard
  • Retry logic and failure notifications matter for your use case

Handling Long-Running Agents Reliably

Whether you choose Modal or Trigger.dev, there are a few patterns worth building into any production agent deployment.

Set Explicit Tool Allowlists

The allowedTools option in the query() function limits what Claude can do. Always be explicit about this — don’t leave it open-ended in production:

options: {
  allowedTools: ["read_file", "bash", "write_file"],
  // Never allow network access unless you specifically need it
}

Cap maxTurns to Avoid Runaway Sessions

Without a turn cap, a confused agent can loop indefinitely. Set maxTurns based on the complexity of your task:

  • Simple analysis tasks: 10–15 turns
  • Complex coding tasks: 20–30 turns
  • Open-ended research: consider breaking into sub-tasks instead

Stream Events to a Database or Queue

Don’t just wait for the final result. Stream events to a database (Postgres, Supabase, etc.) or a queue (Redis, SQS) as they arrive. This gives you a complete audit trail and lets you resume or inspect failed sessions.

Use Environment Isolation

One coffee. One working app.

You bring the idea. Remy manages the project.

WHILE YOU WERE AWAY
Designed the data model
Picked an auth scheme — sessions + RBAC
Wired up Stripe checkout
Deployed to production
Live at yourapp.msagent.ai

Each agent session should run in a clean environment. Avoid sharing file system state between concurrent sessions. On Modal, this means using ephemeral volumes or explicitly scoping paths per-task. On Trigger.dev, use task-scoped temp directories.


Where MindStudio Fits Into This Workflow

The Claude Agent SDK is powerful, but it’s a developer tool — you need to write code, manage deployments, handle infrastructure, and wire up integrations yourself. That’s the right approach for custom agent pipelines, but it creates real overhead when you’re trying to build quickly or hand off agent management to non-technical teammates.

MindStudio takes a different path. It’s a no-code platform where you can build agents that reason across multiple steps, call external APIs, send emails, generate content, and integrate with tools like HubSpot, Notion, Slack, and Airtable — without writing any infrastructure code.

The part most relevant here: MindStudio’s Agent Skills Plugin (@mindstudio-ai/agent) lets any agent — including one built on the Claude Agent SDK — call 120+ typed capabilities as simple method calls. Things like agent.sendEmail(), agent.searchGoogle(), and agent.runWorkflow() work without you building any of that infrastructure yourself.

If you’re running Claude agents via Modal or Trigger.dev and want to add capabilities like image generation, web search, or CRM updates without building custom tool implementations, the MindStudio plugin handles the plumbing so your agent can focus on reasoning.

You can try MindStudio free at mindstudio.ai.


Common Mistakes and How to Avoid Them

Underestimating Execution Time

Agent tasks almost always run longer than you expect in development. In production, add a 3–5x buffer to your timeout settings. A task that takes 2 minutes locally may take 8–10 minutes in a constrained environment.

Not Handling API Rate Limits

If you’re running multiple agent sessions concurrently, you’ll hit Anthropic’s rate limits fast. Use Trigger.dev’s concurrency controls or Modal’s function-level concurrency settings to cap parallel sessions at a safe number.

Logging Only Final Output

Log every event from the agent loop, not just the final result. When something goes wrong mid-session, you need the full trace to understand what happened. Both platforms support structured logging — use it from the start.

Using the SDK Without a Sandboxed Environment

Claude’s bash tool can execute arbitrary commands. In production, always run agent sessions in isolated environments (containers, VMs, or restricted user accounts). Never give agents access to credentials, databases, or production systems directly.


Frequently Asked Questions

What is the Claude Agent SDK?

The Claude Agent SDK (@anthropic-ai/claude-code) is an npm package from Anthropic that exposes Claude Code’s agentic loop as a programmable API. It lets you run Claude as an autonomous agent — capable of using tools like bash, file reads, and web search — from your own code rather than interactively in a terminal.

How long can a Claude agent session run on Modal or Trigger.dev?

On Modal, you can set timeouts up to 24 hours, making it suitable for very long-running agent tasks. On Trigger.dev v3, the maximum task duration is currently one hour. For most agentic workloads, this is sufficient — but if you’re building pipelines that need to run longer, Modal is the better choice.

Hire a contractor. Not another power tool.

Cursor, Bolt, Lovable, v0 are tools. You still run the project.
With Remy, the project runs itself.

Do I need to manage containers or servers to deploy the Claude Agent SDK?

No. Both Modal and Trigger.dev handle infrastructure automatically. You define your function or task in code, deploy it with a CLI command, and the platform manages scaling, execution, and availability. You pay for compute time used, not idle servers.

Can I run Claude agent sessions in parallel?

Yes, both platforms support concurrent execution. Modal scales function invocations horizontally by default. Trigger.dev lets you configure concurrency limits per task. Be mindful of Anthropic’s API rate limits — set concurrency caps to stay within your quota tier.

How do I trigger a Claude agent from an external webhook?

On Modal, use the @modal.web_endpoint decorator to expose your function as an HTTPS endpoint that accepts POST requests. On Trigger.dev, define your task and use their webhook infrastructure to connect it to external events from GitHub, Stripe, Slack, or any custom source.

Is the Claude Agent SDK free to use?

The SDK itself is open source and free. You pay for Anthropic API usage (billed per token, based on your Claude plan) and separately for your serverless platform (Modal or Trigger.dev have their own pricing). Both Modal and Trigger.dev have free tiers that are sufficient for experimentation.


Key Takeaways

  • The Claude Agent SDK exposes Claude Code’s full tool loop as a callable API, enabling production-grade agent deployments
  • Modal is the better fit for Python teams, GPU workloads, and tasks that may exceed one hour — Trigger.dev is better for TypeScript teams that need event-driven triggers and rich observability
  • Always set explicit tool allowlists, maxTurns caps, and environment isolation for production agent sessions
  • Stream agent events to a persistent store from the start — you’ll need the full trace when debugging failures
  • Platforms like MindStudio can complement SDK-based agents by handling capabilities (email, search, image generation) that would otherwise require building custom tool integrations

If you’d rather skip the infrastructure work and build production-ready agentic workflows visually, MindStudio offers a no-code path that connects to 1,000+ tools out of the box — with Claude and 200+ other models available without managing any API keys yourself.

Presented by MindStudio

No spam. Unsubscribe anytime.