# Class LittleGhost::SessionStore

Documentation version: Edge

Canonical HTML: https://littleghostai.org/docs/LittleGhost/SessionStore.html

SessionStore connects LittleGhost conversations to application persistence.
Subclass it to keep sessions in a database, remote service, or other durable
store.

    class DatabaseSessionStore < LittleGhost::SessionStore
      def load(id, actor_id: nil)
        Conversation.find_by(external_id: id, actor_id:)&.snapshot
      end

      def append(id, messages:, state:, metadata:, expected_count:, actor_id: nil)
        Conversation.append!(
          id, messages:, state:, metadata:, expected_count:, actor_id:
        )
      end

      def replace(id, messages:, state:, metadata:, actor_id: nil)
        Conversation.replace!(id, messages:, state:, metadata:, actor_id:)
      end
    end

A snapshot contains `:messages`, `:state`, and
`:metadata`. State and metadata cross this boundary as deeply
string-keyed JSON mappings. Sessions expose the same data through DataMap,
which accepts String or Symbol keys. Implementations provide #load, #append,
and #replace; #append must check `expected_count` atomically so two writers
cannot silently lose a turn.

Actor identity always comes from the caller. A store must not infer it from
ambient process state.

## Inheritance

`LittleGhost::SessionStore < Object`

## Class methods

<a id="method-c-new"></a>
### `.new`

```ruby
.new()
```

Prepares the per-session synchronization used by #synchronize.

## Instance methods

<a id="method-i-append"></a>
### `#append`

```ruby
#append(_id, messages:, state:, metadata:, expected_count:, actor_id: nil)
```

Atomically appends sanitized messages and stores canonical JSON state and
metadata. Implementations raise ProtocolError if the persisted message count
differs from `expected_count`.

<a id="method-i-load"></a>
### `#load`

```ruby
#load(_id, actor_id: nil)
```

Finds the snapshot for `id`, or returns nil when it does not exist.

<a id="method-i-project_conversation"></a>
### `#project_conversation`

```ruby
#project_conversation(_id, messages:, metadata:, actor_id: nil)
```

Stores may expose a clean conversational view without changing the stored
session transcript. The default implementation is a no-op.

<a id="method-i-replace"></a>
### `#replace`

```ruby
#replace(_id, messages:, state:, metadata:, actor_id: nil)
```

Replaces the complete snapshot for `id` atomically with canonical JSON state
and metadata.

<a id="method-i-synchronize"></a>
### `#synchronize`

```ruby
#synchronize(id, actor_id: nil)
```

Serializes work for one actor/session key within this store instance.

<a id="method-i-with_operation_context"></a>
### `#with_operation_context`

```ruby
#with_operation_context(_operation_id)
```

Wraps a store operation with an optional telemetry parent operation. Custom
stores may override this while preserving the block's return value.
