# `ClaudeWrapper.Session`
[🔗](https://github.com/genagent/claude_wrapper_ex/blob/main/lib/claude_wrapper/session.ex#L1)

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

# `t`

```elixir
@type t() :: %ClaudeWrapper.Session{
  config: ClaudeWrapper.Config.t(),
  history: [ClaudeWrapper.Result.t()],
  query_opts: keyword(),
  session_id: String.t() | nil
}
```

# `fork`

```elixir
@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 `t: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.

# `last_result`

```elixir
@spec last_result(t()) :: ClaudeWrapper.Result.t() | nil
```

Get the last result, if any.

# `new`

```elixir
@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

# `resume`

```elixir
@spec resume(ClaudeWrapper.Config.t(), String.t(), keyword()) :: t()
```

Resume an existing session by ID.

# `send`

```elixir
@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 `t: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.

# `session_id`

```elixir
@spec session_id(t()) :: String.t() | nil
```

Get the session ID (if established).

# `stream`

```elixir
@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.

# `total_cost`

```elixir
@spec total_cost(t()) :: float()
```

Get the total cost across all turns.

# `turn_count`

```elixir
@spec turn_count(t()) :: non_neg_integer()
```

Get the number of completed turns.

# `turns`

```elixir
@spec turns(t()) :: [ClaudeWrapper.Result.t()]
```

Get the conversation history (list of results).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
