Multi-turn session management.
Wraps repeated Query.execute/2 calls, automatically threading the
session_id returned by the CLI so each turn continues the same
conversation.
Usage
config = ClaudeWrapper.Config.new(working_dir: "/path/to/project")
session = ClaudeWrapper.Session.new(config)
{:ok, session, result} = ClaudeWrapper.Session.send(session, "What files are in this project?")
{:ok, session, result} = ClaudeWrapper.Session.send(session, "Now add tests for lib/foo.ex")
# Access history
ClaudeWrapper.Session.turns(session)
#=> [%Result{...}, %Result{...}]
# Resume a previous session
session = ClaudeWrapper.Session.resume(config, "session-id-abc")
Summary
Functions
Branch the conversation into a new, independent session.
Get the last result, if any.
Create a new session with the given config.
Resume an existing session by ID.
Send a message in the session. Returns the updated session and result.
Get the session ID (if established).
Send a message and return a stream of events.
Get the total cost across all turns.
Get the number of completed turns.
Get the conversation history (list of results).
Types
@type t() :: %ClaudeWrapper.Session{ config: ClaudeWrapper.Config.t(), history: [ClaudeWrapper.Result.t()], query_opts: keyword(), session_id: String.t() | nil }
Functions
@spec fork(t(), String.t() | ClaudeWrapper.Prompt.t(), keyword()) :: {:ok, t(), ClaudeWrapper.Result.t()} | {:error, ClaudeWrapper.Error.t()}
Branch the conversation into a new, independent session.
Resumes the session's current session_id with --fork-session and
sends prompt. The CLI clones the prior context into a new session;
the returned Session is bound to that new forked id, while the
original struct passed in is left completely untouched -- you can keep
using it to continue the original thread.
prompt accepts a string or a ClaudeWrapper.Prompt.t/0, exactly
like send/3.
Returns {:error, %ClaudeWrapper.Error{kind: :no_session}} if the
session has no established session_id yet (nothing to fork from --
send at least one turn first).
Example
{:ok, session, _} = ClaudeWrapper.Session.send(session, "Draft a plan")
{:ok, branch, _} = ClaudeWrapper.Session.fork(session, "Now try a riskier variant")
# `session` still points at the original thread; `branch` is the fork.
@spec last_result(t()) :: ClaudeWrapper.Result.t() | nil
Get the last result, if any.
@spec new( ClaudeWrapper.Config.t(), keyword() ) :: t()
Create a new session with the given config.
Options
Any option accepted by ClaudeWrapper.query/2 (query-level options only):
:model- Model name:system_prompt- System prompt:max_turns- Max turns per send:permission_mode- Permission mode:max_budget_usd- Budget limit:effort- Effort level
@spec resume(ClaudeWrapper.Config.t(), String.t(), keyword()) :: t()
Resume an existing session by ID.
@spec send(t(), String.t() | ClaudeWrapper.Prompt.t(), keyword()) :: {:ok, t(), ClaudeWrapper.Result.t()} | {:error, ClaudeWrapper.Error.t()}
Send a message in the session. Returns the updated session and result.
The first turn creates a new session. Subsequent turns use --resume
with the session ID from the first result.
prompt is either a plain string or a ClaudeWrapper.Prompt.t/0. A
Prompt is rendered (which expands attached files and git diffs)
before the turn runs; a render failure short-circuits to
{:error, %ClaudeWrapper.Error{}} without launching the CLI.
Get the session ID (if established).
@spec stream(t(), String.t(), keyword()) :: {t(), Enumerable.t()}
Send a message and return a stream of events.
Returns {session, stream}. The returned session is the same
session passed in -- this function does not thread session_id
across turns. If you need multi-turn continuity, use send/3
instead, which runs the turn synchronously and updates
session_id from the final result.
Use stream/3 when you want to observe events from a single turn
(for example, to render intermediate output as the CLI produces
it) and do not need to chain into a follow-up turn on the same
session.
Get the total cost across all turns.
@spec turn_count(t()) :: non_neg_integer()
Get the number of completed turns.
@spec turns(t()) :: [ClaudeWrapper.Result.t()]
Get the conversation history (list of results).