Skip to main content
The Agent SDK gives you the same tools, agent loop, and context management that power Claude Code. It’s available as a CLI for scripts and CI/CD, or as Python and TypeScript packages for full programmatic control. To run Claude Code in non-interactive mode, pass -p with your prompt and any CLI options:
This page covers using the Agent SDK via the CLI (claude -p). For the Python and TypeScript SDK packages with structured outputs, tool approval callbacks, and native message objects, see the full Agent SDK documentation.

Basic usage

Add the -p (or --print) flag to any claude command to run it non-interactively. All CLI options work with -p, including: This example asks Claude a question about your codebase and prints the response:

Start faster with bare mode

Add --bare to reduce startup time by skipping auto-discovery of hooks, skills, plugins, MCP servers, auto memory, and CLAUDE.md. Without it, claude -p loads the same context an interactive session would, including anything configured in the working directory or ~/.claude. Bare mode is useful for CI and scripts where you need the same result on every machine. A hook in a teammate’s ~/.claude or an MCP server in the project’s .mcp.json won’t run, because bare mode never reads them. Only flags you pass explicitly take effect. This example runs a one-off summarize task in bare mode and pre-approves the Read tool so the call completes without a permission prompt:
In bare mode Claude has access to the Bash, file read, and file edit tools. Pass any context you need with a flag: Bare mode skips OAuth and keychain reads. For Anthropic authentication, set ANTHROPIC_API_KEY or configure an apiKeyHelper in the JSON you pass to --settings. Amazon Bedrock, Google Cloud’s Agent Platform, and Microsoft Foundry use their usual provider credentials.
--bare is the recommended mode for scripted and SDK calls, and will become the default for -p in a future release.

Background tasks at exit

If Claude starts a background Bash task during a claude -p run, for example a dev server or a watch build, that shell is terminated about five seconds after Claude has returned its final result and stdin has closed. The grace period lets a task that finishes right after the result still deliver its output. Before v2.1.163, a never-exiting background process would hold the claude -p invocation open indefinitely. Background subagents and workflows are exempt from the five-second grace because their result is part of the final output, so claude -p waits for them to complete. From v2.1.182, that wait is capped at ten minutes by default so a stuck background agent cannot hold the process open indefinitely. Adjust the cap with CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS, or set it to 0 to wait without a limit. If you stop a claude -p run with SIGTERM, for example from kill, a process supervisor, or an SDK host closing the session, Claude Code aborts the in-progress turn, terminates the process tree of any running Bash command, runs SessionEnd hooks, and exits with code 143.

Examples

These examples highlight common CLI patterns. For CI and other scripted calls, add --bare so they don’t pick up whatever happens to be configured locally.

Pipe data through Claude

Non-interactive mode reads stdin, so you can pipe data in and redirect the response out like any other command-line tool. This example pipes a build log into Claude and writes the explanation to a file:
With --output-format json, the response payload includes total_cost_usd and a per-model cost breakdown, so scripted callers can track spend per invocation without consulting the usage dashboard.
As of Claude Code v2.1.128, piped stdin is capped at 10MB. If you exceed the cap, Claude Code exits with a clear error and a non-zero status. To work with larger inputs, write the content to a file and reference the file path in your prompt instead of piping it.
If Claude Code can’t read stdin, for example because the process that started it disconnected its end, Claude Code prints a warning to stderr and continues with the prompt from the command line. Before v2.1.211, an unreadable stdin on Windows crashed the session or made it exit silently with no output.

Add Claude to a build script

You can wrap a non-interactive call in a script to use Claude as a project-specific linter or reviewer. This package.json script pipes the diff against main into Claude and asks it to report typos. Piping the diff means Claude doesn’t need Bash permission to read it, and the escaped double quotes keep the script portable to Windows:

Get structured output

Use --output-format to control how responses are returned:
  • text (default): plain text output
  • json: structured JSON with result, session ID, and metadata
  • stream-json: newline-delimited JSON for real-time streaming
This example returns a project summary as JSON with session metadata, with the text result in the result field:
To get output conforming to a specific schema, use --output-format json with --json-schema and a JSON Schema definition. The response includes metadata about the request (session ID, usage, etc.) with the structured output in the structured_output field. This example extracts function names and returns them as an array of strings:
If the value isn’t a valid JSON Schema, claude exits with Error: --json-schema is not a valid JSON Schema followed by the validator’s diagnostic. Claude Code accepts schemas that use the format keyword, such as "format": "email", but treats format as an annotation and doesn’t enforce it. Before v2.1.205, Claude Code silently ignored an invalid schema and returned unstructured text, and treated any schema containing format as invalid.
Use a tool like jq to parse the response and extract specific fields:

Stream responses

Use --output-format stream-json with --verbose and --include-partial-messages to receive tokens as they’re generated. Each line is a JSON object representing an event:
The last line of the stream is a result message with the final response text, cost, and session metadata. If your consumer reads the stream slowly, Claude Code waits for the queued output to drain before exiting, scaling the wait with how much is still queued, capped at 30 seconds. Before v2.1.214 the exit wait was capped at about two seconds, which could cut off the end of a large response. The following example uses jq to filter for text deltas and display just the streaming text. The -r flag outputs raw strings (no quotes) and -j joins without newlines so tokens stream continuously:
For programmatic streaming with callbacks and message objects, see Stream responses in real-time in the Agent SDK documentation.

Follow subagent messages

Messages from subagents appear in the stream as assistant and user messages whose parent_tool_use_id field is the ID of the tool call that spawned the subagent. Messages from the main conversation carry null in that field. By default, Claude Code emits only subagent tool_use and tool_result blocks. Pass --forward-subagent-text or set CLAUDE_CODE_FORWARD_SUBAGENT_TEXT to also emit subagent text and thinking blocks, so you can reconstruct each subagent’s transcript. This requires Claude Code v2.1.211 or later. When you enable either option, Claude Code forwards messages from subagents at every nesting depth: when a subagent spawns its own subagent, the nested subagent’s messages carry the ID of the Agent tool call that spawned it in parent_tool_use_id, so you can rebuild the full nesting tree by following those IDs. Before v2.1.219, messages from nested subagents didn’t appear in the stream.

Handle API retries

When an API request fails with a retryable error, Claude Code emits a system/api_retry event before retrying. You can use this to surface retry progress or implement custom backoff logic.

Read session metadata

The system/init event reports session metadata including the model, tools, MCP servers, and loaded plugins. It is the first event in the stream unless startup events precede it: The event also carries an optional capabilities array of strings naming the protocol behaviors this Claude Code version implements, such as interrupt_receipt_v1 or interrupt_cancel_queued_v1. Check it to feature-detect instead of comparing version strings, and ignore values you don’t recognize. The field requires Claude Code v2.1.205 or later and is absent from earlier versions. See SDKSystemMessage for the capability list.

Fail CI when a plugin or MCP server doesn’t load

Use the plugin fields in the system/init event to catch a plugin that didn’t load: Use the MCP server fields the same way. Claude Code validates each --mcp-config entry at startup and skips entries that fail validation, for example a url entry with no type; the run continues and exits cleanly, so check these fields to catch a server that never loaded: When you run the command by hand in a terminal, Claude Code also prints a startup warning to stderr, such as Warning: 1 MCP server skipped due to invalid config:, followed by the reason for each skipped entry. When you redirect stderr, or when a program such as a CI runner or an SDK host captures it, Claude Code prints no warning and reports the skipped entries only in the mcp_server_errors field. The warning requires Claude Code v2.1.219 or later.

Track plugin installs

When CLAUDE_CODE_SYNC_PLUGIN_INSTALL is set, Claude Code emits system/plugin_install events while marketplace plugins install before the first turn. Use these to surface install progress in your own UI.

Auto-approve tools

Use --allowedTools to let Claude use certain tools without prompting. This example runs a test suite and fixes failures, allowing Claude to execute Bash commands and read/edit files without asking for permission:
To set a baseline for the whole session instead of listing individual tools, pass a permission mode. dontAsk denies anything not in your permissions.allow rules or the read-only command set, which is useful for locked-down CI runs. AskUserQuestion, connector tools your organization set to ask, and MCP tools marked requiresUserInteraction are denied even when an allow rule matches. acceptEdits lets Claude write files without prompting and also auto-approves common filesystem commands such as mkdir, touch, mv, and cp. Other shell commands and network requests still need an --allowedTools entry or a permissions.allow rule, otherwise the run aborts when one is attempted:

Create a commit

This example reviews staged changes and creates a commit with an appropriate message:
The --allowedTools flag uses permission rule syntax. The trailing * enables prefix matching, so Bash(git diff *) allows any command starting with git diff. The space before * is important: without it, Bash(git diff*) would also match git diff-index.
User-invoked skills and custom commands work in -p mode: include /skill-name in the prompt string and Claude Code expands it before running. Built-in commands that only run in the terminal interface, such as /login, aren’t available in -p mode. /model, /effort, /fast, /color, and /rename accept the value as an argument, for example /model sonnet, and /mcp with no argument prints a text summary of server status; these forms require Claude Code v2.1.205 or later and follow each command’s availability notes. To change a setting from a -p invocation, pass key=value to /config, for example /config thinking=false.

Customize the system prompt

Use --append-system-prompt to add instructions while keeping Claude Code’s default behavior. This example pipes a PR diff to Claude and instructs it to review for security vulnerabilities:
See system prompt flags for more options including --system-prompt to fully replace the default prompt.

Continue conversations

Use --continue to continue the most recent conversation, or --resume with a session ID to continue a specific conversation. This example runs a review, then sends follow-up prompts:
If you’re running multiple conversations, capture the session ID to resume a specific one:
Run both commands from the same directory: session ID lookup is scoped to the current project directory and its git worktrees. See Resume a session for the full scope rules.

Next steps