NAME
Claude::Agent::Query - One conversation with the Claude Code CLI
SYNOPSIS
use Claude::Agent::Query;
use Claude::Agent::Options;
my $query = Claude::Agent::Query->new(
prompt => "Find all TODO comments",
options => Claude::Agent::Options->new(
allowed_tools => ['Read', 'Glob', 'Grep'],
),
);
while (my $msg = $query->next) {
if ($msg->isa('Claude::Agent::Message::Result')) {
print $msg->result, "\n";
last;
}
}
my $future = $query->next_async;
DESCRIPTION
A query starts the claude CLI as a child process, speaks the SDK control protocol with it over its standard streams, and delivers the messages it emits as Claude::Agent::Message objects. The query() function of Claude::Agent builds one.
The CLI is started with --output-format stream-json --input-format stream-json. The first thing written to it is an initialize control request carrying the hook registrations and agent definitions; the prompt is written as a user message once the CLI has answered. Hooks, can_use_tool and in-process MCP servers are served from the CLI's control_request messages. Standard input is closed as soon as the prompt is sent unless one of those is in use, in which case it stays open until the turn's result arrives and the CLI reports itself idle.
ATTRIBUTES
prompt
The first user message: a string, or an ArrayRef of content blocks. May be left unset for a session that will send its first message later.
options
A Claude::Agent::Options. Defaults to an empty one.
loop
An IO::Async::Loop to run on. One is created when none is given; pass your application's loop for event-driven use.
persistent
Keep standard input open across turns. Claude::Agent::Client sets it.
spawn, writer, closer
Test seams. With spawn => 0 no process is started: every line that would go to the CLI is passed to writer as ($line, $data), closing standard input calls closer, and feed_line injects the CLI's output.
METHODS
new
Takes a flat list of name/value pairs. Unknown names are ignored. The CLI is located (cli_path, PATH, then the usual install locations) and started before new returns; a CLI older than $Claude::Agent::Query::MINIMUM_CLAUDE_CODE_VERSION is warned about. Set CLAUDE_AGENT_SDK_SKIP_VERSION_CHECK to skip the probe.
next
my $msg = $query->next;
Blocks until the next message, returning undef when the process has finished. Waits at most the query_timeout option (default 600 seconds) and then records a timeout in error.
next_async
my $msg = await $query->next_async;
A Future of the next message, resolving to undef when the process has finished.
send_user_message
$query->send_user_message("Continue", session_id => $id);
Write a user message. Returns true when written.
interrupt, interrupt_async
Ask the CLI to stop the current turn.
set_permission_mode, set_permission_mode_async
$query->set_permission_mode('acceptEdits');
set_model, set_model_async
$query->set_model('sonnet');
set_max_thinking_tokens, set_max_thinking_tokens_async
$query->set_max_thinking_tokens(8000);
rewind_files, rewind_files_async
$query->rewind_files($result->user_message_uuid);
Undo file changes back to a prompt. Needs the enable_file_checkpointing option.
mcp_status, mcp_status_async
The CLI's MCP server status report.
get_context_usage, get_context_usage_async
The CLI's context window usage breakdown.
reconnect_mcp_server, reconnect_mcp_server_async
$query->reconnect_mcp_server('github');
Ask the CLI to reconnect an MCP server.
toggle_mcp_server, toggle_mcp_server_async
$query->toggle_mcp_server('github', 0);
Enable or disable an MCP server for the session.
stop_task, stop_task_async
$query->stop_task($task_id);
Stop a background task.
Every _async method returns a Future of the CLI's response hash, failing with the CLI's error text, on timeout (60 seconds), or when the query is not running. The plain form runs the loop until the Future is ready and returns the response, or undef on failure.
server_info
The CLI's answer to the initialize request, once the query has started. On Claude Code 2.1.300 it carries commands, models, output_style, available_output_styles, account, capabilities, claude_code_version, current_permission_mode, session_state, fast_mode_state and pid.
supported_commands, supported_models, output_style, available_output_styles
Fields of server_info.
session_id
The session id, once the CLI's init message has arrived.
cli_version
my $version = $query->cli_version;
The version the claude -v probe reported for the CLI in use, if it ran. Takes an optional path to ask about another CLI.
is_finished
True once the process has exited.
error
The error text if the process failed, timed out, or could not initialize.
close, close_async
$query->close;
Stop the process: an interrupt request, then standard input is closed, then SIGINT, SIGTERM and SIGKILL at five second intervals until it exits. Pending Futures are resolved.
cleanup
An alias for close, kept from 0.13.
feed_line
$query->feed_line($json);
Process one line as if the CLI had written it. A test seam.
ENVIRONMENT
The child inherits the environment with CLAUDECODE removed and CLAUDE_CODE_ENTRYPOINT, CLAUDE_AGENT_SDK_VERSION and CLAUDE_CODE_SDK_READS_SESSION_STATE set; the env option is applied over it. CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS (default 600000, 0 for none) bounds how long standard input stays open after a result while the CLI still reports background work. CLAUDE_AGENT_JSONL_BUFFER_MAX caps the partial-line buffer.
AUTHOR
LNATION, <email at lnation.org>
LICENSE
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under The Artistic License 2.0 (GPL Compatible).