Skip to main content
query() is the primary entry point for running Claude Code programmatically. It accepts a prompt (or a stream of user messages), runs the agent loop, and returns an AsyncIterable of typed SDK messages you can process as they arrive.

Signature

function query(params: {
  prompt: string | AsyncIterable<SDKUserMessage>
  options?: Options
}): Query
Query is an AsyncIterable<SDKMessage> — iterate it with for await to receive messages in real time.

Parameters

prompt
string | AsyncIterable<SDKUserMessage>
required
The user prompt to send to Claude. Pass a plain string for a single prompt, or an AsyncIterable<SDKUserMessage> to stream multiple user turns (useful for multi-turn pipelines driven externally).
options
Options
Configuration for the agent run. All fields are optional.

Return type

query() returns a Query, which is an AsyncIterable<SDKMessage>. Each yielded value is a discriminated union on type:
type
string
Message type. Key variants:
  • 'system' — session initialization, status, compaction boundaries, and other lifecycle events.
  • 'assistant' — a model response (text, tool use, thinking blocks).
  • 'user' — a user turn (echoed back in the stream).
  • 'result' — the terminal message emitted when the agent loop ends.
  • 'stream_event' — raw streaming events from the model.
  • 'tool_progress' — progress notification from a long-running tool.
  • 'rate_limit_event' — rate limit status change.

Result message

The final message in the stream always has type: 'result'. It has a subtype field:
subtype
'success' | 'error_during_execution' | 'error_max_turns' | 'error_max_budget_usd' | 'error_max_structured_output_retries'
Outcome of the agent run.
result
string
The final text response from Claude (only present when subtype is 'success').
is_error
boolean
Whether the run ended in an error state.
num_turns
number
Number of agentic turns taken.
total_cost_usd
number
Total API cost in US dollars.
duration_ms
number
Wall-clock duration of the entire run in milliseconds.
session_id
string
Session ID for this run, usable with resumeSession() or getSessionMessages().

Non-interactive / print mode

query() is the SDK equivalent of running claude -p "..." on the command line. No interactive TTY is required — output is delivered as structured messages over the async iterator rather than being rendered to a terminal.
Set maxTurns to limit how many API round-trips the agent makes. Without a limit, the agent continues until it decides it is done or hits a context limit.

Complete example

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

async function analyzeProject(projectPath: string): Promise<string> {
  let finalResult = ''

  const stream = query({
    prompt: 'Analyze this codebase and summarize the main architectural patterns.',
    options: {
      cwd: projectPath,
      model: 'claude-opus-4-5',
      maxTurns: 10,
      allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],
      permissionMode: 'acceptEdits',
      appendSystemPrompt: 'Focus on TypeScript patterns. Be concise.',
    },
  })

  for await (const message of stream) {
    // Print assistant text as it streams
    if (message.type === 'assistant') {
      for (const block of message.message.content) {
        if (block.type === 'text') {
          process.stdout.write(block.text)
        }
      }
    }

    // Capture the final result
    if (message.type === 'result' && message.subtype === 'success') {
      finalResult = message.result
      console.log(`\n\nCompleted in ${message.num_turns} turns, cost: $${message.total_cost_usd.toFixed(4)}`)
    }

    // Handle errors
    if (message.type === 'result' && message.subtype !== 'success') {
      throw new Error(`Agent failed: ${message.subtype}`)
    }
  }

  return finalResult
}

analyzeProject('/path/to/my/project').catch(console.error)

Streaming user messages

For multi-turn scenarios where the user input arrives asynchronously (e.g. from a WebSocket), pass an AsyncIterable<SDKUserMessage> as prompt:
import { query } from '@anthropic-ai/claude-code'
import type { SDKUserMessage } from '@anthropic-ai/claude-code'

async function* userMessageStream(): AsyncIterable<SDKUserMessage> {
  yield {
    type: 'user',
    message: { role: 'user', content: 'Hello! What files are in the current directory?' },
    parent_tool_use_id: null,
  }
  // Additional user messages can be yielded here as they arrive
}

const stream = query({
  prompt: userMessageStream(),
  options: { cwd: '/path/to/project', model: 'claude-opus-4-5' },
})

for await (const message of stream) {
  // process messages...
}