> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flow.engineer/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Agent SDK

> Run a Claude agent for each message and deliver its streamed answer.

Run a Claude agent for each incoming message and deliver its answer as chat bubbles. Your agent keeps its tools; Flow handles the channel connection.

```ts TypeScript theme={null}
// npm install @flow-engineer/messaging @anthropic-ai/claude-agent-sdk
import { query } from "@anthropic-ai/claude-agent-sdk";
import { FlowMessaging, contentText } from "@flow-engineer/messaging";

const flow = new FlowMessaging();

for await (const event of flow.events.stream({ types: ["message.received"] })) {
  const run = query({
    prompt: contentText(event.data.message.content),
    options: {
      systemPrompt: "You are the assistant for Asha's Bakery. Answer customers in short messages.",
      tools: [], // no built-in tools (Bash, file access); list the ones your agent may use
      includePartialMessages: true, // stream text as it is written
    },
  });
  await event.conversation.reply(run); // sends the agent's text, skips tool and system messages
}
```

```python Python (HTTP) theme={null}
# pip install claude-agent-sdk requests
# Plain HTTP, no Flow SDK; the Python SDK (pip install flow-messaging) wraps the same calls. This calls the HTTP API.
import os, requests
from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, TextBlock

API = "https://api.flow.engineer"
HEADERS = {"Authorization": f"Bearer {os.environ['FLOW_MESSAGING_KEY']}"}

async def answer(event: dict):
    conversation = event["conversation"]["id"]
    text = event["data"]["message"]["content"].get("text", "")
    options = ClaudeAgentOptions(
        system_prompt="You are the assistant for Asha's Bakery. Answer in short messages.",
        tools=[],  # no built-in tools; list the ones your agent may use
    )
    i = 0
    async for message in query(prompt=text, options=options):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock) and block.text.strip():
                    requests.post(
                        f"{API}/v0/conversations/{conversation}/basic",
                        headers={**HEADERS, "Idempotency-Key": f"{event['id']}:{i}"},
                        json={"text": block.text},  # sent exactly as written: no markdown is rendered
                        timeout=30,
                    )
                    i += 1
```

## How it fits

* `reply()` reads the `query()` iterator: with `includePartialMessages` it sends text as it streams, otherwise each assistant message's text. Tool calls, results and system messages are not sent to the person.
* Each assistant turn becomes its own bubble, which reads naturally in chat ("Let me check that..." then the answer).
* `tools: []` turns off Claude Code's built-in tools, which a customer-facing agent should not have by default; `allowedTools` only pre-approves tools and does not restrict them.
* Keep one Claude session per Flow conversation (`conversation.id`) to carry context between messages: remember each run's `session_id` and pass it as `resume` next time (the full example does this).
* Your production agent talks to Flow through the SDK or HTTP. The [hosted MCP server](https://docs.flow.engineer/unified-messaging-api/mcp.md) is a separate build-time tool for coding agents; whether a project adds it is the project owner's decision.
* To see each turn's model and tool calls and get every reply graded, send this agent's traces to Flow Observe: [Traces from agent frameworks](https://docs.flow.engineer/unified-messaging-api/observe/frameworks.md).

## Full example

[examples/claude-agent-sdk](https://github.com/flow-engineer/sdk/tree/main/examples/claude-agent-sdk) on GitHub.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.