NAME

Claude::Agent::Client - Multi-turn session with the Claude Code CLI

SYNOPSIS

use Claude::Agent::Client;
use Claude::Agent::Options;

my $client = Claude::Agent::Client->new(
    options => Claude::Agent::Options->new(
        allowed_tools => ['Read', 'Glob', 'Grep'],
    ),
);

$client->connect("Help me understand this codebase");
while (my $msg = $client->receive) {
    if ($msg->isa('Claude::Agent::Message::Result')) {
        print "Result: ", $msg->result, "\n";
        last;
    }
    elsif ($msg->isa('Claude::Agent::Message::Assistant')) {
        print "Claude: ", $msg->text, "\n";
    }
}

$client->send("Now find all TODO comments");
my @turn = $client->receive_until_result;

$client->set_permission_mode('acceptEdits');
$client->disconnect;

DESCRIPTION

A client keeps one CLI process alive for a whole conversation. Each send writes another user message to it and each turn ends with a Claude::Agent::Message::Result. The session() function of Claude::Agent builds one.

ATTRIBUTES

options

A Claude::Agent::Options. Defaults to an empty one.

loop

An IO::Async::Loop to run on.

query_args

Extra arguments for the Claude::Agent::Query the client creates, for tests: spawn, writer, closer.

METHODS

new

Takes a flat list of name/value pairs. Unknown names are ignored.

connect

$client->connect($prompt);
$client->connect;

Start the process and send the first prompt, if given. Dies when already connected.

resume

$client->resume($session_id, $prompt);

Start the process on an earlier session.

fork

$client->fork($session_id, $prompt);

As resume, but under a new session id.

send

$client->send($content, session_id => $id);

Write a user message: a string or an array of content blocks. The session id defaults to default, which the CLI reads as the current session.

receive

my $msg = $client->receive;

The next message, or undef when the process has ended.

receive_async

A Future of the next message.

receive_until_result

my @messages = $client->receive_until_result;

Every message up to and including the next result. Stops after CLAUDE_AGENT_MAX_MESSAGES messages (default 1000, at most 5000).

is_connected

True between connect and disconnect.

session_id

The session id, once the CLI has reported it.

query

The underlying Claude::Agent::Query, or undef.

server_info

The CLI's initialize response, once the query has started.

interrupt, set_permission_mode, set_model, set_max_thinking_tokens, rewind_files, mcp_status, get_context_usage, reconnect_mcp_server, toggle_mcp_server, stop_task

Delegate to the query; see Claude::Agent::Query. When the client is not connected they return undef.

interrupt_async, set_permission_mode_async, set_model_async, set_max_thinking_tokens_async, rewind_files_async, mcp_status_async, get_context_usage_async, reconnect_mcp_server_async, toggle_mcp_server_async, stop_task_async

The same, returning a Future, which fails when the client is not connected.

disconnect

$client->disconnect;

Stop the process and forget the session. Safe to call more than once.

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).